OAuth Authentication in Salesforce

by Dakota Larson

OAuth Authentication in Salesforce

Over the past few weeks, I have been diving into OAuth Authentication as part of my internship here at Sundog Interactive. The following is a relatively complete synopsis of journey developing an application that authenticates users using Salesforce OAuth Authentication.

OAuth authentication can be challenging to implement. This guide is designed to help during the development of such an app, and detail the various steps I went through to get my app running. OAuth authentication has numerous benefits for user security and heavily reduces the amount of responsibility that you have to your users. OAuth flows are everywhere, so understanding how they work is definitely worth your time. This is a Salesforce (SFDC) implementation of such a flow.

 

Salesforce Connected App Setup

To start off creating an application that requires OAuth authentication using Salesforce, a Connected App needs to be created. On your Salesforce Organization (Org) setup page, navigate to the “Apps” page which can be found by typing “Apps” into the Quick Find field or by navigating to “Build” -> “Create” -> “Apps”.

Then on the “Apps” page, navigate to the “Connected Apps” section. Click “New”. You should now be on this page:

Make sure to check “Enable OAuth Settings”, otherwise, the settings for “Callback URL” and “Selected OAuth Scopes” won’t be visible. The “Callback URL” is used during the final step in the authentication process. Unless another URL is needed, use “https://login.salesforce.com/services/oauth2/success”. While you can visit this page in a browser, your application users will never see this page during the authentication process. Finally, select the “OAuth Scopes” that you need for your application. Since I was creating an application that would need users’ Chatter Data, I selected “(chatter_api)”. If you are creating an application that uses Refresh Tokens, then you must include “(refresh_token, offline_access)”. In your list of scopes, or the Refresh Token process will fail. Finally, click “Save”. You will be prompted by this lovely message:

Click “Continue”.

You will now be presented with this page:

Here is where you can view the “Consumer Key”, “Callback URL”, and the “Consumer Secret”. You can navigate to this page from Setup -> Build -> Create -> Apps, and then click on your application title in the“Connected Apps” section. Your application will be displayed there. This is where you will make changes to the app on the Salesforce side if needed.

Once the Connected App is created, you can start integrating authentication into your application!

Application Authentication Integration (Coding)

Depending upon the app you are developing, the steps you take may be different from mine. The general idea however, should remain largely the same.

OAuth Flows

Salesforce offers three OAuth flows:

  • Web Server flow
    • Used when the “Consumer Secret” can be protected.
    • Used primarily on Web Servers (Hence the name)
  • User-Agent flow
    • Used when the “Consumer Secret” cannot be protected.
    • Used primarily in Desktop Applications
  • Username-Password flow
    • Used only when other OAuth flows are not applicable.
    • Application has direct access to user credentials (Not ideal even in the best cases)

Consumer Secret Protection

The “Consumer Secret” is included in the code for desktop applications. Since this is put in the hands of users, it cannot be considered “protected”. Users do not have access to web servers. Since the “Consumer Secret” is stored on that server, it is considered “protected”.

My Application Specifics

  • OAuth Flow: User-Agent
  • Desktop Application
  • Created with Electron (https://electron.atom.io/)
  • Created with Node.js (Javascript)

Authentication Flow Specifics

Salesforce provides guides for each authentication flow that it provides. Here is the diagram that Salesforce provides for the User-Agent flow:

Before starting, it is a smart idea to use an app such as Postman to debug the requests you are making. This allows you to gain a deeper understanding of both the requests you are making, and the responses you are receiving.

First Steps!

The first step in the process is directing the user to the SFDC Authorization Endpoint. As it turns out, the endpoints are different for different types of Salesforce Organizations.

Sandbox Organizations: https://test.salesforce.com/services/oauth2/authorize

Developer and Production Organizations: https://login.salesforce.com/services/oauth2/authorize

As you can see, the only difference between the URLs is the subdomain. If neither of these URLs work for you, then use the subdomain of the webpage you use to log in to the organization. For example, when I am logging into my personal, developer org, I use https://login.salesforce.com/. Therefore, I would use the Authentication URL for Developer and Production Organizations as the subdomain matches.

In addition to the URL, several parameters need to be provided in the request:

  • “response_type”: For the User-Agent flow, set this as “token”
  • “client_id”: The “Consumer Key” specified in the connected app
  • “redirect_uri”: The “Callback URL” specified in the connected app

Additionally, some other parameters can be included which include “display”, “scope” and “state”. As these are non-essential, consult SFDC documentation for a better understanding of them.

Implementing the First Request

Here is my initial request using the “Request” module that is part of Node.js:

The second parameter of the request function is a callback function which is called when the request completes. Since I was using Electron, I found the most seamless authentication integration was through an additional popup window. This also explains the use of the additional display parameter. I found “popup” had the best look for my implementation (as expected).

Interestingly, the request when sent correctly responds with a 302 status code (A temporary redirect). The request module is capable of following redirects, however, I decided that I would create the popup window only when the initial request was complete. The popup window loads the page specified in the response headers.

At this point, the user submits their username and password into the popup window and completes the rest of the verification process. It ends on this page:

It is here that the Selected OAuth Scopes that were chosen when creating the app are presented. In my case, I requested access to Chatter data and the ability to use Refresh Tokens. Access to basic information is implemented by default. Regardless of what option the user selects, the page is directed to our “Callback URL”.

Concluding the User-Agent Flow

In this last step, the first point of business is to check whether the user granted access to our app or not. If the user denied access, then a URL similar to https://login.salesforce.com/services/oauth2/success?error=access_denied&error_description=end-user+denied+authorization&display=popup is received.

In contrast a successful response looks similar to this (Taken (trimmed) from SFDC Documentation):   https://login.salesforce.com/services/oauth2/success#access_token=00Dx0000000BV7z%21&refresh_token=5Aep8614iLM.Dq661ePD

A proper successful response will include additional parameters which include:

  • “access_token”: Similar to a session ID; included with every request for resources
  • “refresh_token”: Token used to retrieve new access tokens through a “Refresh Token Process”. According to SFDC documentation, the refresh token is only sent if the Callback URL is https://login.salesforce.com/services/oauth2/success.
  • “instance_url”: URL where requests for resources should be sent
  • id: URL that provides basic information for the user. A valid access token must be included as a parameter in this request.
  • “issued_at”: Timestamp of when the signature was created.
  • “signature”: According to SFDC documentation: “Base64-encoded HMAC-SHA256 signature signed with the consumer’s private key containing the concatenated ID and issued_at value. The signature can be used to verify that the identity URL wasn’t modified because it was sent by the server.”

Needless to say, the signature documentation is a bit of a mouthful. Essentially, it is an additional layer of security so that you can verify the response received is legitimate. Here is my verification function:

Additionally, here is a  callbackURL handler including parsing the URL and completing verification:

It is important that the refresh token is saved in a secure fashion. The refresh token should be treated with the same level of security as a username and password combination.

Now with refresh token and access token in hand, protected resources can now be accessed. Here is an example of a request for protected resources using the Chatter API:

As you can see, the access token is included in the header of the request. It must be included for every request that is made for protected resources.

Refresh Token Process

Access Tokens, much like sessions are usable for a certain period before they expire. In my use case, having the user reauthenticate multiple times during the day is completely unacceptable. If this is true for you, then you need to use Refresh Tokens. Luckily the process is relatively straight forward, and only involves one request/response pair. As with the Authentication flow, Salesforce provides a guide for helping navigate this process.

Connected App Setup

Remember that the connected app that you are using in Salesforce needs to have the “(refresh_token, offline_access)” OAuth Scope enabled, or this process will fail.

Refresh Token Request

Similar to the initial Authentication Flow request, the initial request for the Refresh Token Process has a URL that varies depending upon what type of organization you are using.

Developer and Production Organizations: https://login.salesforce.com/services/oauth2/authorize

Sandbox Organizations: https://test.salesforce.com/services/oauth2/authorize

Remember that if you log into your salesforce organization with a URL that contains a different subdomain (something other than “login” or “test”), then that subdomain is likely used here as well.

Once you have determined the URL that you will be using for the request, you can assemble the rest of your parameters. These parameters are:

  • “grant_type”: Must be “refresh_token”
  • “refresh_token”: The refresh token that was received as part of the authentication flow
  • “client_id”: The “Consumer Key” specified in the connected app
  • “client_secret”: The “Consumer Secret” specified in the connected app

Additionally, you can add a “format” parameter if you wish to receive your response in a format other than JSON. When a response is received, it should be verified in the same manner as with the authentication flow.

Here is an example of the code that I used to request a new access token:

The function that I use has a callback function as one of the arguments. That is called when the response is received and verified. In contrast to the response received during the authentication flow, this response is encoded in JSON by default. Given that I am working with Javascript, this made parsing the response significantly easier.

The response includes several parameters:

  • “access_token”: The new access token that function similar to a session ID
  • “instance_url”: The URL where all requests for content should be directed
  • “id”: A URL that when accessed provides basic user information
  • “issued_at”: Timestamp of when the signature was created
  • “signature”: According to SFDC documentation: “Base64-encoded HMAC-SHA256 signature signed with the consumer’s private key containing the concatenated ID and issued_at value. The signature can be used to verify that the identity URL wasn’t modified because it was sent by the server.” (I included a verification function snippet earlier in this post)

Error Handling:

  • Remember to check if the user even has an internet connection first. If they aren’t online, then there is no point in making a request.
  • “Error” responses are not consistent. They may be URL encoded, JSON encoded, or just a string.
  • Users can log in 3600 times per hour which shouldn’t cause any issues, however, they can only generate new access tokens 5 times per hour. Additionally, only 5 access tokens can be stored in your Salesforce Organization per app. These can be revoked in “My Settings” -> “Personal” -> “Connections”.

From here, you should be able to code an application that allows users to Authenticate using OAuth and have the application re-authenticate them on their behalf while the application is running!

 

Recent Posts

Privacy In JavaScript
Dakota Larson

Archives

Categories