Digging Deeper into OAuth 2.0 on Force.com
Abstract
OAuth (Open Authorization) is an open protocol to allow secure API authorization in a simple and standardized way from desktop, web applications. The Force.com platform implements the OAuth 2.0 Authorization Framework, so users can authorize applications to access Force.com resources (via the Force.com REST and SOAP Web Service APIs) on their behalf without revealing their passwords or other credentials to those applications. Alternatively, applications can directly authenticate to access the same resources outside the context of an end user.
This article takes an in-depth look at the latest version of the OAuth 2.0 protocol in the context of Force.com, and is intended for developers and architects with an understanding of security and identity concepts such as authentication and authorization. If you're looking for more of an overview of OAuth 2.0 on Force.com, then Getting Started with the Force.com REST API is a great place to start.
OAuth 2.0 Basics
OAuth is often described as a 'valet key for the web'. In the same way as a valet key gives restricted access to a car, allowing the valet to drive it but not open the trunk or glovebox, OAuth allows a client application restricted access to your data at a resource server via tokens issued by an authorization server in response to your access grant.
The OAuth Internet-Draft uses the example of a photo sharing web site (for example, Flickr) as the resource server and a printing service (for example, Snapfish) as the client. You might authorize the printing service (client) for read-only access to some subset of your photos for a limited period of time, after which the access grant becomes invalid. You can even instruct the authorization server to revoke an access token if you decide you no longer wish the client to have access, and don't trust it to discontinue on its own.
Contrast this with the common case of giving your credentials (username and password) to a client app so it can access a resource server on your behalf, effectively impersonating you directly. That application now has exactly the same access as you have, to all of your data. Worse, if you decide you no longer trust the client app, your only recourse is to change your password at the resource server and at all the similar client apps you wish to continue using - a major inconvenience! As the previous paragraph shows, OAuth provides a much better solution.
OAuth 2.0 on Force.com
Salesforce.com introduced support for Draft 10 of OAuth 2.0 in the Winter '11 release of Force.com; this version continues to be supported in more recent releases. Most OAuth 2.0 references and terminology in this article refer to OAuth 2.0 Draft 10. A future release will add support for the final specification, now that it is an RFC.
As a Force.com developer, you can use OAuth 2.0 via one of six authentication flows. The most important of these are:
- Web Server - users can authorize your web application to access their data, as described above. This is the OAuth web server profile using an access grant type of authorization_code.
- User-Agent - users can authorize your desktop or mobile application to access their data, leveraging an external or embedded browser (or user-agent) for authentication - the OAuth native application profile. No access grant type is specified. This profile is referred to as the user-agent authentication flow in the Salesforce.com documentation.
- SAML Assertion - your application can authenticate by presenting a SAML 2.0 assertion to Force.com, the OAuth 2.0 assertion access grant type.
- Username and Password - your application can authenticate directly to Force.com using an 'API user's credentials - the password access grant type, also known as the username-password flow.
(There is also the Refresh Token flow, described in detail below, for renewing tokens issued by the web server or user-agent flows, and the OAuth 1.0a flow, described in Using OAuth to Authorize External Applications).
Note that you should avoid the username/password flow wherever possible, since the other flows free your application from having to manage, store and protect user credentials, but be careful - if you use the web server profile you must store the client secret securely.
You should only use the password access grant type in situations such as an autonomous client, where a user cannot be present at application startup. In this instance, you should carefully set the API user's permissions to minimize its access as far as possible, and protect the API user's stored credentials from unauthorized access. Such protection is out of the scope of this article, but, for example, you should at least ensure that, if the API user's password is stored in a file on disk, it is not readable by all!
Tokens, tokens, everywhere!
There are a number of different types of token defined by OAuth 2.0. They each serve a distinct purpose in the protocol, and it's worth taking a few minutes to ensure you understand the differences between them.
Authorization Code
An authorization code is a short-lived token representing the user's access grant, created by the authorization server and passed to the client application via the browser. The client application sends the authorization code to the authorization server to obtain an access token and, optionally, a refresh token.
Access Token
The access token is used by the client to make authenticated requests on behalf of the end user. It has a longer lifetime than the authorization code, typically on the order of minutes or hours. When the access token expires, attempts to use it will fail, and a new access token must be obtained via a refresh token.
In Force.com terms, the access token is effectively a SID or 'session', much like a session cookie on other systems, and should be protected against interception, for example by Transport Layer Security (TLS, aka SSL).
Note that if you want to use an OAuth token to access the Force.com Web UI on behalf of the user, either by setting a SID cookie or via the 'front door' URL (e.g. https://na1.salesforce.com/secur/frontdoor.jsp?sid=<sid_value>) you must include web in the list of requested scopes - see the discussion on the scope parameter in the web server flow section below.
Refresh Token
The refresh token may have an indefinite lifetime, persisting until explicitly revoked by the end-user. The client application can store the refresh token, using it to periodically obtain fresh access tokens, but should be careful to protect it against unauthorized access, since, like a password, it can be repeatedly used to gain access to the resource server.
Since refresh tokens may expire or by revoked by the user outside the control of the client application, the client must handle failure to obtain an access token, typically by replaying the protocol from the start.
Configuring OAuth 2.0 Access for your Application
Applications using the OAuth 2.0 web server, user-agent or username-password flows must be configured in the Force.com administration console as a Remote Access Application (the assertion flow does not require this). For example, if you have a Developer Edition account, log in to Force.com with your developer credentials, navigate to Setup ➤ Develop ➤ Remote Access, and click New to create a new remote access application.
The 'Callback URL' field, also known as the 'redirect URI', is an endpoint in your application to which Force.com can redirect the user's browser with an authentication code. To protect the authentication code, the Callback URL cannot have 'http' as its scheme - it must be 'https' or a custom URI scheme (often used in the user-agent flow to pass control back to a native application). After entering your application's details and clicking Save, you will see your new application’s credentials:
Click the link to reveal the consumer secret. Note – OAuth 1.0 terminology is currently used in the Remote Access screen. Both the OAuth 2.0 specification and this article use the term ‘client’ in place of ‘consumer’.
Obtaining an Access Token in a Web Application (Web Server Flow)
Most web applications will use the web server client profile and authorization code access grant type to obtain an access token on behalf of an end user.
The sequence starts (1) with a user requesting some service from the client - in our hypothetical photo-printing example above, the user would be requesting that the photo-printing site print a particular photo.
The client application responds by (2) redirecting the end user's browser to a URL of the following form:
https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id=<your_client_id>&redirect_uri=<your_redirect_uri>
The following parameters are required (all must be URL encoded):
response_type
| Must be set to "code" to request an authorization code. |
client_id
| Your application's client identifier (consumer key in Remote Access Detail). |
redirect_uri
| The end user's browser will be redirected to this URI with the authorization code. This must match your application's configured callback URL. |
The following optional parameters may also be supplied (again, URL encoded):
display
| Tailors the login page to the user's device type. Currently the only values supported are:
|
immediate
| Avoid interacting with the user.
|
scope
| A space separated list of scope values. The scope parameter allows you to fine-tune what the client application can access. Supported values are:
If you do not supply a |
state
| Any value that you wish to be sent with the callback in step 4. |
Assuming immediate is not set, or is set to false, on reaching this login URL, the user will be prompted to authenticate (3) and, if they have not already done so, authorize the client application:
On successful authorization, the user's browser is redirected back to the redirect URI at the client application (4), with a URL of the form:
https://app.example.com/oauth_callback?code=aWekysIEeqM9PiThEfm0Cnr6MoLIfwWyRJcqOqHdF8f9INokharAS09ia7UNP6RiVScerfhc4w%3D%3D
The client application can now extract the authorization code from its URL parameter and send a direct POST request (5) to the authorization server with URL https://login.salesforce.com/services/oauth2/token and payload of the form
code=aWekysIEeqM9PiThEfm0Cnr6MoLIfwWyRJcqOqHdF8f9INokharAS09ia7UNP6RiVScerfhc4w==&grant_type=authorization_code&client_id=<your_client_id>&client_secret=<your_client_secret>&redirect_uri=<your_redirect_uri>
The following parameters are required (again, URL encoded):
code
| The value returned by the authorization server in the previous step. |
grant_type
| Set this to authorization_code. |
client_id
| Your application's client identifier. |
client_secret
| Your application's client secret (consumer secret in Remote Access Detail). |
redirect_uri
| Again, this must match your application's configuration. |
The authorization server should respond with an HTTP status code of 200 and JSON-encoded response payload (reformatted for readability):
{
"id":"https://login.salesforce.com/id/00D50000000IZ3ZEAW/00550000001fg5OAAQ",
"issued_at":"1296458209517",
"refresh_token":"5Aep862eWO5D.7wJBuW5aaARbbxQ8hssCnY1dw3qi59o1du7ob.lp23ba_3jMRnbFNT5R8X2GUKNA==",
"instance_url":"https://na1.salesforce.com",
"signature":"0/1Ldval/TIPf2tTgTKUAxRy44VwEJ7ffsFLMWFcNoA=",
"access_token":"00D50000000IZ3Z!AQ0AQDpEDKYsn7ioKug2aSmgCjgrPjG9eRLza8jXWoW7uA90V39rvQaIy1FGxjFHN1ZtusBGljncdEi8eRiuit1QdQ1Z2KSV"
}
id
| A URL, representing the authenticated user, which can be used to access the Identity Service. |
issued_at
| The time of token issue, represented as the number of seconds since the Unix epoch (00:00:00 UTC on 1 January 1970). |
refresh_token
| A long-lived token that may be used to obtain a fresh access token on expiry of the access token in this response. See Token Refresh for more details. |
instance_url
| Identifies the Salesforce instance to which API calls should be sent. |
signature
| Base64-encoded HMAC-SHA256 signature signed with the consumer's private key containing the concatenated ID and issued_at. This can be used to verify the identity URL was not modified since it was sent by the server. |
access_token
| The short-lived access token. |
At this point, the client application can use the access token to authorize requests against the resource server (the Force.com instance specified by the instance URL) via the REST APIs (6), providing the access token as an HTTP header in each request:
Authorization: Bearer 00D50000000IZ3Z!AQ0AQDpEDKYsn7ioKug2aSmgCjgrPjG...
(For an explanation of 'Bearer' in this context, see section 1.2 of RFC 6750, The OAuth 2.0 Authorization Framework: Bearer Token Usage.)
The client can continue to send requests to the resource server until the access token expires (8, 9, 10).
The Force.com Identity Service
The 'id' URI that accompanies the access token and instance URL is the gateway to Force.com's Identity Service. You can send a GET request to the id URI, accompanied by an OAuth authorization HTTP header containing the access token, and receive a wealth of information regarding the user and org:
{
"id":"https://login.salesforce.com/id/00D50000000IZ3ZEAW/00550000001fg5OAAQ",
"asserted_user":true,
"user_id":"00550000001fg5OAAQ",
"organization_id":"00D50000000IZ3ZEAW",
"username":"user@example.com",
"nick_name":"user1.2950476911907334E12",
"display_name":"Sample User",
"email":"user@example.com",
"status":{
"created_date":"2010-11-08T20:55:33.000+0000",
"body":"Working on OAuth 2.0 article"
},
"photos":{
"picture":"https://c.na1.content.force.com/profilephoto/005/F",
"thumbnail":"https://c.na1.content.force.com/profilephoto/005/T"
},
"urls":{
"enterprise":"https://na1.salesforce.com/services/Soap/c/{version}/00D50000000IZ3Z",
"metadata":"https://na1.salesforce.com/services/Soap/m/{version}/00D50000000IZ3Z",
"partner":"https://na1.salesforce.com/services/Soap/u/{version}/00D50000000IZ3Z",
"rest":"https://na1.salesforce.com/services/data/v{version}/",
"sobjects":"https://na1.salesforce.com/services/data/v{version}/sobjects/",
"search":"https://na1.salesforce.com/services/data/v{version}/search/",
"query":"https://na1.salesforce.com/services/data/v{version}/query/",
"recent":"https://na1.salesforce.com/services/data/v{version}/recent/",
"profile":"https://na1.salesforce.com/00550000001fg5OAAQ"
},
"active":true,
"user_type":"STANDARD",
"language":"en_US",
"locale":"en_US",
"utcOffset":-28800000,
"last_modified_date":"2011-01-14T23:28:01.000+0000"
}
Let's take a closer look at some of the more interesting fields in that response:
asserted_user
| true if this is the user corresponding to the supplied OAuth token. |
user_id
| The user's Salesforce.com ID. |
organization_id
| The user's org ID. |
username
| The user's login username. |
display_name
| The user's name as displayed in the Salesforce.com user interface. |
email
| The user's email address. |
status
| The user's Chatter status. |
photos
| URLs to access the user's picture and thumbnail. |
urls
| URLs for a range of API endpoints. |
Obtaining an Access Token in a Native Application (User-Agent Flow)
Client applications, for example, JavaScript running in the browser or native mobile or desktop apps, run on a user's computer or other device. Such apps are able to protect per-user secrets, but, since they are widely distributed, a common client secret would not be secure. The user-agent flow allows these applications to obtain an access token:
In this flow, the client application directs (1) the user to a URL at the authorization server of the form:
https://login.salesforce.com/services/oauth2/authorize?response_type=token&
client_id=<your_client_id>&redirect_uri=<your_redirect_uri>&display=touch&state=<some_state>
The following parameters are required (all must be URL encoded):
response_type
| Must be set to "token" to request an access token. |
client_id
| Your application's client identifier (consumer key in Remote Access Detail). |
redirect_uri
| The authorization server will respond with a redirect to this URI. This parameter must match your application's configured callback URL. |
The following optional parameters may also be supplied (again, URL encoded):
display
| Tailors the login page to the user's device type. Currently the only values supported are:
|
scope
| A space separated list of scope values; see the web server flow for details. |
state
| Any value that you wish to be sent with the callback in step 3. |
As in the web server flow, the user is authenticated and prompted to authorize the client application's access to resources (2):
Now, rather than sending an authentication code to the client and it retrieving the access token via a POST request, a redirect is returned (3) containing several parameters in a URL fragment (i.e. after the hash '#' sign) - for example:
myapp:oauth#access_token=00D50000000IZ3Z%21AQ0AQI6qUiQpGCAlNVAEOugF7J6Lr34LHSUUQZ_S4rnPzShAsJzG0qjW1XEx5R6kDORlWE2r9QXJpfAkAkq8V9k_V0PbXYjN&refresh_token=5Aep861eQO5D.6wJBuW5bbARbbxQ8hssCnY1dw3qi59jeys7ob.H_xM395_RJHukNjeustDru8BiA%3D%3D&instance_url=https%3A%2F%2Fna3.salesforce.com&id=https%3A%2F%2Flogin.salesforce.com%2Fid%2F00D50000000IZ3ZEAW%2F00550000001fg5OAAQ&issued_at=1298926970349&signature=Y5ici2QZsudYyH%2F4YWcJd1s3P89mLJPVsO0plVoHD4o%3D&state=mystate
access_token
| The short-lived access token. |
refresh_token
| A long-lived token that may be used to obtain a fresh access token on expiry of the access token in this response. See Token Refresh for more details. Note that refresh_token is only sent if either of the following is the case:
|
instance_url
| Identifies the Salesforce instance to which API calls should be sent. |
id
| A URL, representing the authenticated user, which can be used to access the Identity Service. |
issued_at
| The time of token issue, represented as the number of seconds since the Unix epoch (00:00:00 UTC on 1 January 1970). |
signature
| Base64-encoded HMAC-SHA256 signature signed with the consumer's private key containing the concatenated ID and issued_at. This can be used to verify the identity URL was not modified since it was sent by the server. |
state
| If a value was provided for the state parameter in the request, then that same value will be returned here.
|
Since these parameters are passed in a fragment, they will remain on the client device, and will not be passed in an HTTP GET to the redirect URI. Note that the redirect URI may have a custom scheme, configured in the desktop/device OS to invoke a callback in the native app, for example, myapp:oauth, or it may have the https scheme.
A native application can directly parse the incoming parameters from the fragment; in contrast a browser-based application would rely on JavaScript, served from the https redirect URI, which would have access to the fragment and its parameters.
Either way, on receipt of the access token, the client application is able to send requests to the resource server (the Force.com instance specified by the instance URL) via the REST APIs (6), providing the access token as an HTTP header in each request:
Authorization: Bearer 00D50000000IZ3Z!AQ0AQDpEDKYsn7ioKug2aSmgCjgrPjG...
Token Refresh
The lifetime of an access token obtained by the above mechanisms is limited to the session timeout configured in Setup ➤ Security Controls ➤ Session Settings. When an access token expires, attempts to use it (2) will result in an error response (3) with a 401 HTTP status code and a JSON-encoded body of
[ { message: 'Session expired or invalid'
, errorCode: 'INVALID_SESSION_ID'
}
]
In this situation, the client application can use the refresh token to obtain a new access token. The refresh token represents the user's access grant to the application, and is valid until explicitly revoked by the user, via Setup ➤ My Personal Information ➤ Remote Access.
The client application obtains a new access token by POSTing another request (4) to https://login.salesforce.com/services/oauth2/token, this time with payload of the form:
grant_type=refresh_token&client_id=3MVG9lKcPoNINVBJGKrUKSXjJRTgKoeZx6OvJLXwLO8n80_OY.ydx0cQ24zGwBhRfa4YEWrFaNVVdI142EivZ&client_secret=7868057769520845245&refresh_token=5Aep861eWO5D.7wJBuW5aaARbbxQ8hssCnY1dw3qi59o1du7ob.lp23ba_3jMRnbFNT5R8X2GUKNA==
| grant_type | Set this to refresh_token. |
| client_id | Your application's client identifier. |
| client_secret | Your application's client secret (optional). |
| refresh_token | The refresh token provided in the previous access grant. |
On receipt of the access token, the client can repeat its request (5), send a response to the user (6), and carry on servicing requests (7, 8, 9) until the new access token expires.
Obtaining a Token in an Autonomous Client (Username-Password Flow)
An autonomous client can obtain an access token by simply providing username, password and (depending on configuration) security token in an access token request. Again the request is POSTed (1) to https://login.salesforce.com/services/oauth2/token, but the payload now has the form
grant_type=password&client_id=<your_client_id>&client_secret=<your_client_secret>&username=<your_username>&password=<your_password>
The following parameters are required:
| grant_type | Set this to password. |
| client_id | Your application's client identifier. |
| client_secret | Your application's client secret. |
| username | The API user's Salesforce.com username, of the form user@example.com. |
| password | The API user's Salesforce.com password. If the client's IP address has not been whitelisted in your org, you must concatenate the security token with the password. |
You will receive a similar response to the authorization code case:
{
"id":"https://login.salesforce.com/id/00D50000000IZ3ZEAW/00550000001fg5OAAQ",
"issued_at":"1296509381665",
"instance_url":"https://na1.salesforce.com",
"signature":"+Nbl5EOl/DlsvUZ4NbGDno6vn935XsWGVbwoKyXHayo=",
"access_token":"00D50000000IZ3Z!AQgAQH0Yd9M51BU_rayzAdmZ6NmT3pXZBgzkc3JTwDOGBl8BP2AREOiZzL_A2zg7etH81kTuuQPljJVsX4CPt3naL7qustlb"
}
You will notice that there is no refresh token in the response. Since the user is not redirected to login at Salesforce, there is no opportunity for the user to authorize the application. Such an authorization is required for a refresh token to be issued. If your application requires a refresh token, you should carefully consider moving to either the web server or user agent flow if at all possible.
Summary
Force.com's implementation of OAuth 2.0 allows client applications to access resources on behalf of end users without sharing credentials such as passwords with those client applications, enhancing both privacy and security. This article provides a description of OAuth as well as the various authentication flows supported by OAuth.
References
- OAuth Community Site
- The OAuth 2.0 Protocol (Draft 10)
- RFC 6749 - The OAuth 2.0 Authorization Framework
- RFC 6750 - The OAuth 2.0 Authorization Framework: Bearer Token Usage
- Salesforce.com OAuth Documentation
- Getting Started with the Force.com REST API
- Building Android Applications with the Force.com REST API
About the Author
Pat Patterson is a relatively recent addition to the Developer Evangelism team at salesforce.com. Describing himself as an 'articulate techie', Pat hacks all manner of code from Ruby web apps down to Linux kernel drivers, writing it all up on the Force.com blog, his own blog Superpatterns, tweeting along the way.








