[SalesForce] Unable to retrieve context in canvas app when authenticating with oauth

I’m having trouble authenticating my canvas app using oauth2. This is despite being able to authenticate and connect via other means. The following is my problem in detail…

I’ve configured a connected app with the following settings…

OAuth Scope: full, refresh_token, offline_access
Canvas App URL: https://app.d.com/ (this is a locally-running server)
Canvas Access Method: OAuth Webflow (GET)
SAML Initiation Method: None
Locations: Chatter Tab, Visualforce Page, Layouts and Mobile Cards
Options: Enabled as a Canvas Personal App
Lifecycle Class: None

Using OAuth and the jsForce library on the backend, I’m able to authenticate with Salesforce and push events from our web app to a chatter stream. During the authentication process, I save the user’s auth token and refresh token (so that I am able to continue to make calls via the backend).

However, when plugging the Sfdc library into the front end and attempting to access my web app via canvas, I am unable to get the context object. Here is some debugging code (in coffeescript) that I trigger when the web app is loaded via canvas…

initCanvas: (session) =>
    if !Sfdc.canvas.oauth.loggedin()
      debugger
      uri = Sfdc.canvas.oauth.loginUrl()
      Sfdc.canvas.oauth.login({
        uri: uri
        params: {
          response_type: "token"
          client_id: SALESFORCE_API_KEY
          redirect_uri: SALESFORCE_REDIRECT_URI
        }
      })
    else
      debugger
      Sfdc.canvas.oauth.logout()

Ideally, since I already have the user’s auth token (when they enable chatter integration), I shouldn’t need to trigger the Sfdc.canvas.oauth.login() function. I should be able to get the context by creating my own client object. But since I am trying to follow the examples as closely as possible, let’s proceed with the assumption that I’m using the code above…

When the canvas app loads within salesforce, my first “debugger” breakpoint gets hit. After playing through this breakpoint, I receive a salesforce popup window which asks me to authenticate. After authenticating, the canvas app appears to refresh (because it hit the example callback.html endpoint provided) and now my second breakpoint gets hit (after the else statement). At this point, my client object looks like the following…

{
  instanceId: undefined,
  oauthToken: "00Do0000000...Ce7F2kJx”, // shortened for this example
  targetOrigin: undefined
}

Unfortunately, it appears that I need the instanceId and targetOrigin, because when I try to request the context…

Sfdc.canvas.client.ctx(function (msg) { console.log(msg); }, client);

I get back the following error…

{status: 400, statusText: "Bad Request", parentVersion: undefined, payload: "client.instanceId or client.targetOrigin not supplied”}

This response comes from the Sfdc library, not any salesforce server. Any attempts to modify the instanceId and targetOrigin fields directly on the client object do not appear to work either…

client = {oauthToken: "00Do0000000…Ce7F2kJx”, instanceId: “06Po0000000LRQb”, targetOrigin: “https://na17.salesforce.com”};

Sfdc.canvas.client.ctx(function (msg) { console.log(msg); }, client);

Response…

undefined

(no callback msg received in the console)

Looking at the documentation, the instanceId and targetOrigin are defined as…

instanceId: The ID of a canvas app exposed on a Visualforce page. Used internally for canvas app instance management.
targetOrigin: The URL of the canvas app. Used internally for cross-domain communication between the page and the iFrame that contains the canvas app.

Questions…

1.) If the user has already authenticated and given permission to the app, why do we need to request permission a second time?
2.) It appears as though the instanceId and targetOrigin fields are required portions of the client object before being able to request the context via the Sfdc library. How can I obtain these fields?

Best Answer

1.) Technically, if you follow the refresh oauth flow, it isn't necessary to present the user with a new login prompt via the Sfdc.canvas.oauth.loginUrl() method. It is possible to create the client from scratch using the correct oauthToken, targetOrigin, and instanceId params. When one of these parameters is slightly wrong, it is possible for the ctx method to silently fail (as it did above).

2.) To get the correct targetOrigin and instanceId params, it is best to receive them in the hash as part of your canvas app url (ex: https://myapp.com/canvas.html#targetOrigin=xyz&instanceId=abc). In my case, because I was using a front end framework, this hash was stripped upon page load - so I wasn't able to see that they were actually getting sent over.

Related Topic