What is Canvas?

Desk.com Canvas is a mechanism for consuming third-party applications within Desk.com. Its goal is to connect applications at a UI level instead of just an API level.

In short, you host a web page that you develop, and then reveal it in the Desk.com Next Gen UI via a Canvas-type iFrame that you add with Page Layouts. By including the desk-canvas-all.js file in your page, you get access to the entire Canvas JS library Desk.com makes available.

Currently supported methods allow you to call any endpoint in the Desk.com API and refresh the context payload. More and more methods will be added over time.


Using Canvas

We recommend that you use your own tech stack to set up a server that accepts a signed request via POST. The signed request information can be verified with the client secret provided in the Desk Admin page for API tokens (ideally stored on your server as an environment variable) and used to customize the app, and make subsequent calls to Desk.com.

For a quick way to explore Canvas, simply add the desk-canvas-all.js file to an html page hosted on your server and then add a snippet of javascript like this one:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<html>
<head>
  <title>
    Desk Canvas Test
  </title>
  <style media="screen" type="text/css">
  #context {
    background-color: oldlace;
  }
  </style>
</head>
<body>
  <!-- Include the Desk Canvas library, hosted on a CDN for your convenience -->
  <script src="https://ajax.deskapi.com/libs/desk/canvas/1.0.0/desk-canvas-all.js"></script>
  <script>
    Desk.canvas(function() {
      Desk.canvas.client.refreshSignedRequest(function(data) {
        // Grab the response and save it to a variable.
        var signedRequest = data.payload.response;
        // Base64-decode the second part of the signed request.
        var decodedRequest = Desk.canvas.decode(signedRequest.split('.')[1]);
        // The result is a JSON representation of the context. Let's parse that into a Javascript object.
        var contextObj = JSON.parse(decodedRequest);
        // Let's show what we actually get back.
        var contextElem = Desk.canvas.byId('context');
        var greetingElem = Desk.canvas.byId('greeting');
        greetingElem.innerHTML = 'Hi ' + contextObj.context.user.fullName + '!';
        // Using JSON.stringify here because this will look much nicer than just showing `decodedRequest`.
        contextElem.innerHTML = JSON.stringify(contextObj, undefined, 2);
        // We can also store this so we can reference it later without having to use a global variable.
        Desk.canvas.client.signedrequest(contextObj);
      });
    });
  </script>
  <h3 id="greeting"></h3>
  <pre id="context"></pre>
</body>
</html>

When you load this page in the Next Generation Agent as a Canvas/Integration Url field, you'll be presented with the context object. Note: This is suggested for development purposes only. Production servers should be configured to verify the authenticity of signed requests so you can confirm that the information in the context object originated from Desk.com.


Signed Requests

When you use a signed request for authentication in your canvas app, you receive a CanvasRequest object in the initial POST message from Desk.com. This object contains fields related to the request, and also contains the Context and Client objects. The CanvasRequest object is returned in JSON format and contains the following fields.

The signed request is a string of the following elements concatenated:

  • The hash generated as a result of signing the context with the Canvas app consumer secret, using the HMAC SHA–256 algorithm
  • A period (“.”)
  • The context JSON encoded in Base64

The signed request looks similar to this, although it will be much longer: 9Rpl6rE7R2bSNjoSfYdERk8nffmgtKQNhr5U/5eSJPI=.eyJjb250ZXh0Ijp7InVzZXIiOnsibGFuZ3V...

Signed request considerations:

  • Desk.com performs an HTTP POST with the signed request as the body when invoking the canvas app URL.
  • Server-side code is needed to verify and decode the request.
  • Client-side code can be used to decode the request, but for security reasons, should not be used to verify it.

Verifying and Decoding a Signed Request

When using a signed request, Desk.com delivers the user context and authentication information to your canvas app URL. To ensure that the signed request is valid, you must verify that the signed request was signed using your specific canvas app consumer secret. If the correct consumer secret was used, then you can trust the context; otherwise, you can assume that the request was not initiated by Desk.com. To verify and decode the signed request, your application should:

  1. Receive the POST message that contains the initial signed request from Desk.com.
  2. Split the signed request on the first period. The result is two strings: the hashed Based64 context signed with the consumer secret and the Base64 encoded context itself.
  3. Use the HMAC SHA-256 algorithm to hash the Base64 encoded context and sign it using your consumer secret.
  4. Base64 encode the string created in the previous step.
  5. Compare the Base64 encoded string with the hashed Base64 context signed with the consumer secret you received in step 2.

If the two values are the same, then you know that the signed request was signed using your consumer secret and can be trusted. From there, you can Base64 decode the encoded context and parse out any values you need. For more information on those values, refer to the Example CanvasRequest Object section below. If the two strings are different, then the request was not hashed and signed using your consumer secret, and you should return the appropriate message to the user to notify them that the request could not be verified.

Example CanvasRequest Object

The following code snippet shows an example of the CanvasRequest object.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
{
  "currentTime": "Mon, 05 Jan 2015 10:26:14 -0800",
  "expiresAt": "Mon, 05 Jan 2015 10:27:14 -0800",
  "algorithm": "HMACSHA256",
  "userId": "1",
  "client": {
    "targetOrigin": "https://demo.desk.com",
    "instanceUrl": "https://demo.desk.com",
    "oauthToken": "NOTUSED"
  },
  "context": {
    "user": {
      "userId": "1",
      "userName": "agent@desk.com",
      "email": "agent@desk.com",
      "fullName": "Joe Agent",
      "locale": "en_us",
      "language": "en_us",
      "timeZone": "Pacific Time (US & Canada)",
      "roleId": 60,
      "userType": "agent",
      "profileThumbnailUrl": "http://www.gravatar.com/avatar/8a4e3154a0f99458dd1f382e72174198?default=mm&rating=PG&size=50"
    },
    "links": {
      "restUrl": "/api/v2/",
      "userUrl": "/api/v2/users/1"
    },
    "application": {
      "name": "Canvas Demo",
      "canvasUrl": "https://deskcanvasdemo.herokuapp.com/canvas",
      "applicationId": 9,
      "authType": "SIGNED_REQUEST"
    },
    "organization": {
      "organizationId": 1,
      "name": "My Amazing Company"
    },
    "environment": {
      "locationUrl": "https://demo.desk.com/web/agent/case/5000",
      "displayLocation": "CaseLayout",
      "dimensions": {
        "width": "360px",
        "height": "300px",
        "maxWidth": "360px",
        "maxHeight": "1000px",
        "clientWidth": "360px",
        "clientHeight": "300px"
      },
      "case": {
        "id": "5000",
        "url": "/api/v2/cases/5000",
        "channelType": "email"
      },
      "company": {
        "id": "100",
        "url": "/api/v2/companies/100",
        "name": "Acme Inc."
      },
      "customer": {
        "id": "10000",
        "url": "/api/v2/customers/10000",
        "firstName": "Bob",
        "lastName": "Jones",
        "emailAddresses": [
          {
            "type": "home",
            "value": "bob@bobjones.com"
          },
          {
            "type": "work",
            "value": "b.jones@sfdc.com"
          }
        ],
        "phoneNumbers": [
          {
            "type": "home",
            "value": "415-555-1212"
          },
          {
            "type": "work",
            "value": "650-555-1212"
          }

        ],
        "twitterHandle": "@bjones999"
      }
    }
  }
}

currentTime: The timestamp when this context object was generated (used to prevent replay attacks). The timestamp reflects the current time to ensure that the request is not being replayed on your canvas application to gain unauthorized access.
expiresAt: The timestamp when this context object should be considered expired. As a best practice, we recommend checking that the context object has not expired at the moment your application receives it.
algorithm: The algorithm used to sign the request. "HMACSHA256" is currently the only valid value.
userId: The context user's ID.

Client

The Client object is a JSON-formatted object returned by the signed request in the CanvasRequest object. It contains context information about the client app.
instanceUrl: The URL of the Desk.com instance. For example, http://support.desk.com. Used to preface the URLs returned by the Links object.
oauthToken: This field is currently not used and only retained with a placeholder value to improve compatibility with existing Desk.com Canvas applications. targetOrigin: The URL of the canvas app. Used internally for cross-domain communication between the page and the iFrame that contains the canvas app.

Context

The Context object provides information to your app about how and by whom it’s being consumed. You can use this information to make subsequent calls for information and code your app so that it appears completely integrated with the Desk.com agent interface. This object is returned in JSON format and contains the following objects:

User

The User object is a JSON-formatted object containing context information about the current user, such as locale, name, user ID, email, and so on. This information can be used within the canvas app (for example, to display the user’s name) or to make subsequent calls to retrieve additional information.
userId: The ID associated with the current user.
userName: The context user's login username.
email: The context user's email address.
fullName: The context user's full name.
language: The context user’s language. String is 2-5 characters long. The first two characters are always an ISO language code, for example “fr” or “en.” If the value is further qualified by country, then the string also has an underscore (_) and another ISO country code, for example “us” or “uk.” For example, the string for the United States is “en_us,” and the string for French Canadian is “fr_ca.”
locale: The context user's locale.
timeZone: The context user’s time zone.
roleId: The ID of the context user’s currently assigned role.
profileThumbnailUrl: The URL for a thumbnail of the context user’s profile photo taken from Gravatar. If the user does not have a profile picture set up on Gravatar, this link will return a generic thumbnail.
userType: The type of user license assigned to the profile associated with the context user.

Links

The Links object is a JSON-formatted object containing URLs that can be helpful when integrating your canvas app. For example, you can make a GET request to the userUrl to get more information about the current user.
restUrl: URL to return a list of REST API resources.
userUrl: URL for the context user.

Application

The Application object contains canvas app information collected when the application was added as an Integration Url in the Desk.com Admin, such as the Canva url and the assigned Id.
name: The name of the canvas app.
canvasUrl: The URL of the canvas app.
applicationId: The ID of the canvas app.
authType: The access method of the canvas app. "SIGNED_REQUEST" is currently the only valid value.

Organization

The Organization object is a JSON-formatted object containing context information about the organization in which the canvas app is running.
organizationId: The ID of the context organization/site.
name: The name of the context organization.

Environment

The Environment object is a JSON-formatted object containing context information about the canvas app environment. This object contains the dimensions object, the record object, and the displayLocation object.

locationUrl: The URL of the page in Desk.com where the user is accessing the canvas app. For example, if users access your canvas app by navigating to a case, this field contains the URL of that case.
displayLocation: The location in the application where the canvas app is currently being called from. Valid values are:

  • CaseLayout - The canvas app was called as part of a custom field on the case details pane.
  • CustomerLayout - The canvas app was called as part of a custom field on the customer detail pane.
  • CompanyLayout - The canvas app was called as part of a custom field on the company detail pane.
  • CaseInteraction - The canvas app was called as a component of a case interaction.
  • ApplicationLevel - The canvas app was called as a persistent component of Desk.com that is accessible application-wide.
Dimensions

width: The width of the iFrame in pixels.
height: The height of the iFrame in pixels.
maxWidth: The maximum width of the iFrame in pixels.
maxHeight: The maximum height of the iFrame in pixels.
clientWidth: The values of clientWidth are sent to the canvas app within SignedRequest and can be used to set the width of the outermost div element. The field can be referenced as sr.context.environment.dimensions.clientWidth, where sr is the parsed signed request JavaScript object.
clientHeight: The values of clientHeight are sent to the canvas app within SignedRequest and can be used to set the height of the outermost div element. The field can be referenced as sr.context.environment.dimensions.clientHeight, where sr is the parsed signed request JavaScript object.

Case

id: The ID of the current case (if applicable).
url: The URL of the associated case. The format of the URL is the same as the REST API resource for the given case.
channelType: The Channel of the case (e.g., chat, twitter, email, qna, facebook, phone).

Customer

id: The ID of the current customer (if applicable).
url: The URL of the associated customer. The format of the URL is the same as the REST API resource for the given customer.
firstName: The customer's first name.
lastName: The customer's last name.
emailAddresses: Array of email objects, each specifying the contact type and value of the email address.
phoneNumbers: Array of phone number objects, each specifying the contact type and value of the phone number.
twitterHandle: The customer's Twitter handle (including the preceding @ symbol).

Company

id: The ID of the current company (if applicable).
url: The URL of the associated company. The format of the URL is the same as the REST API resource for the given company.
name: The name of the company.


Supported Methods

Canvas v1.0 supports the following methods:

  1. ajax
  2. refreshSignedRequest

ajax(url, settings)

Performs a cross-domain, asynchronous HTTP request to Desk.com.
Note: this method shouldn't be used for same domain requests. Only requests to the Desk.com site are allowed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Replying to a case:
var sr = Desk.canvas.client.signedrequest();
var url = sr.context.environment.case.url+"/replies";
var body = {body: "This is the text for a reply to a case."};
Desk.canvas.client.ajax(url,
  {client : sr.client,
    method: 'POST',
    data: JSON.stringify(body),
    success : function(data) {
    if (201 === data.status) {
      alert("Success");
    }
  });

Parameters:

{String} url

  • The URL to which the request is sent

{Object} settings

  • A set of key/value pairs to configure the request
  • The success setting is required at minimum and should be a callback function

{String} settings.client

  • The required client context {oauthToken: "", targetOrigin : "", instanceId : ""}
  • Simply pass in the client object from the signed request

{String} settings.data Optional

  • The request body

{String} settings.method Optional, Default: GET

  • The type of AJAX request to make

{Function} settings.success Optional

  • Callback for all responses from the server (failure and success). Callback receives a response object containing fields such as data, responseHeaders, status, statusText

Throws:

An error if the URL is missing or the settings object doesn't contain a success callback function.


refreshSignedRequest(cb)

Returns a new signed request via a callback. This method is intended for developers who need to retrieve the signed request by using a more client-side JavaScript approach. (The Desk.com Canvas SDK sends the signed request to your app.)

1
2
3
4
5
6
7
Desk.canvas.client.refreshSignedRequest(function(data) {
    if (data.status === 200) {
        var signedRequest = data.payload.response;
        var part = signedRequest.split('.')[1];
        var obj = JSON.parse(Desk.canvas.decode(part));
    }
})

Parameters:

{Function} callback

  • Callback function that receives the base64 encoded signed request.