OAuth 2.0 JWT Bearer Token Flow

Available in: All Editions

User Permissions Needed
To manage, create, edit, and delete OAuth applications: “Manage Remote Access”

JSON Web Token (JWT) is a JSON-based security token encoding that enables identity and security information to be shared across security domains.

The OAuth 2.0 JWT bearer token flow defines how a JWT can be used to request an OAuth access token from Salesforce when a client wishes to utilize a previous authorization. Authentication of the authorized application is provided by a digital signature applied to the JWT.

More detailed explanations of a JWT and the JWT bearer token flow for OAuth can be found at:

Overview of OAuth 2.0 JWT Bearer Token Flow

The OAuth 2.0 JWT bearer token flow is similar to a refresh token flow within OAuth. The JWT is POSTed to the OAuth token endpoint, which in turn processes the JWT, and issues an access_token based upon prior approval of the application. However, the client doesn’t need to have or store a refresh_token, nor is a client_secret required to be passed to the token endpoint.

JWT bearer flow supports two algorithms: HMAC SHA256 and RSA SHA256. HMAC SHA256 uses the consumer’s secret as the signing secret, while RSA SHA256 uses an uploaded certificate.

The OAuth 2.0 JWT bearer token flow involves the following general steps:
  1. The developer creates a new or uses an existing remote access application and may optionally register an X509 Certificate. This certificate corresponds to the private key of their application. When the remote access application is saved, the Consumer Key (OAuth client_id) and Consumer Secret are generated and assigned to the application.
  2. The developer writes an application that generates a JWT, and signs it with their consumer secret (HMAC) or their certificate (RSA).
  3. The JWT is POSTed to the token endpoint https://login.salesforce.com/services/oauth2/token.
  4. The token endpoint validates the signature using the consumer secret (HMAC) or the certificate registered by the developer (RSA).
  5. The token endpoint validates the audience (aud), issuer (iss), validity (exp), and principal (prn) of the JWT.
  6. Assuming the JWT is valid and the application has been previously authorized by the user or administrator, Salesforce issues an access_token.
    Note
    A refresh_token is never issued in this flow.

Creating a JWT Bearer Token

The developer must create a valid JWT bearer token that conforms to either HMAC SHA256 or RSA SHA256. The following rules are for RSA SHA256; HMAC SHA256 is similar.
  • The issuer (iss) must be the OAuth client_id or the remote access application for which the developer registered their certificate.
  • The audience (aud) must be https://login.salesforce.com or https://test.salesforce.com.
  • The principal (prn) must be the username of the desired Salesforce user.
  • The validity (exp) must be the expiration time of the assertion, within five minutes, expressed as the number of seconds from 1970-01-01T0:0:0Z measured in UTC.
  • The JWT must be signed using RSA SHA256.
  • The JWT must conform with the general format rules specified here: http://tools.ietf.org/html/draft-jones-json-web-token.
To construct a JWT bearer token, do the following:
  1. Construct a JWT Header in the following format: {"alg":"RS256"}.
  2. Base64url encode the JWT Header as defined here: http://tools.ietf.org/html/rfc4648#page-7. The result should be similar to this: eyJhbGciOiJSUzI1NiJ9.
  3. Construct a JSON Claims Set for the JWT with the iss, prn, aud, and exp:
    {"iss": "3MVG99OxTyEMCQ3gNp2PjkqeZKxnmAiG1xV4oHh9AKL_rSK.BoSVPGZHQ
    ukXnVjzRgSuQqGn75NL7yfkQcyy7", 
    "prn": "Pierre_Delacroix@SeattleApps.com", 
    "aud": "https://login.salesforce.com", 
    "exp": "1333685628"}
  4. Base64url encode the JWT Claims Set. For example:
    eyJpc3MiOiAiM01WRzk5T3hUeUVNQ1EzZ05wMlBqa3FlWkt4bm1BaUcxeFY0b0hoO
    UFLT​F9yU0suQm9TVlBHWkhRdWtYblZqelJnU3VRcUduNzVOTDd5ZmtRY3l5NyIsIC
    Jwcm4iOi​AiY2hhcmxpZW1vcnRpbW9yZUBnbWFpbC5jb20iLCAiYXVkIjogImh0dHB
    zOi8vbG9naW4​uc2FsZXNmb3JjZS5jb20iLCAiZXhwIjogIjEzMzM2ODU2MjgifQ
  5. Create a new string for the encoded JWT Header and the encoded JWT Claims Set, in this format:
    encoded_JWT_Header + "." + encoded_JWT_Claims_Set
    In the following example, the encoded JWT Header is highlighted:
    eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiAiM01WRzk5T3hUeUVNQ1EzZ05wMlBqa
    3FlWkt4b​m1BaUcxeFY0b0hoOUFLTF9yU0suQm9TVlBHWkhRdWtYblZqelJnU3V
    RcUduNzVOTDd5Zmt​RY3l5NyIsICJwcm4iOiAiY2hhcmxpZW1vcnRpbW9yZUBnb
    WFpbC5jb20iLCAiYXVkIjogI​mh0dHBzOi8vbG9naW4uc2FsZXNmb3JjZS5jb20
    iLCAiZXhwIjogIjEzMzM2ODU2MjgifQ
  6. Sign the resulting string using SHA256 with RSA.
  7. Create a new string of the string from this step, in the following format:
    existing_string + "." + base64_encoded_signature
    In the following example, the start of the base64 encoded signature is highlighted:
    eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiAiM01WRzk5T3hUeUVNQ1EzZ05wMlBqa3FlWkt4​
    bm1BaUcxeFY0b0hoOUFLTF9yU0suQm9TVlBHWkhRdWtYblZqelJnU3VRcUduNzVOTDd5Z
    ​mtRY3l5NyIsICJwcm4iOiAiY2hhcmxpZW1vcnRpbW9yZUBnbWFpbC5jb20iLCAiYXVkIj
    ​ogImh0dHBzOi8vbG9naW4uc2FsZXNmb3JjZS5jb20iLCAiZXhwIjogIjEzMzM2ODU2Mjg​
    ifQ.iYCthqWCQucwi35yFs-nWNgpF5NA_a46fXDTNIY8ACko6BaEtQ9E6h4Hn1l_pcwcK​
    I_GlmfUO2dJDg1A610t09TeoPagJsZDm_H83bsoZUoI8LpAA1s-2aj_Wbysqb1j4uDToz​
    480WtEbkwIv09sIeS_-QuWak2RXOl1Krnf72mpVGS4WWSULodgNzlKHHyjAMAHiBHIDNt​
    36y2L2Bh7M8TNWiKa_BNM6s1FNKDAwHEWQrNtAeReXgRy0MZgQY2rZtqT2FcDyjY3JVQb​
    En_CSjH2WV7ZlUwsKHqGfI7hzeEvVdfOjH9NuaJozxvhPF489IgW6cntPuT2V647JWi7ng

The follow Java code is a simple example of constructing a JWT bearer token:

import org.apache.commons.codec.binary.Base64;
import java.io.*; 
import java.security.*; 
import java.text.MessageFormat;  

public class JWTExample {

  public static void main(String[] args) {

    String header = "{\"alg\":\"RS256\"}";
    String claimTemplate = "'{'\"iss\": \"{0}\", \"prn\": \"{1}\", \"aud\": \"{2}\", \"exp\": \"{3}\"'}'";

    try {
      StringBuffer token = new StringBuffer();

      //Encode the JWT Header and add it to our string to sign
      token.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8")));

      //Separate with a period
      token.append(".");

      //Create the JWT Claims Object
      String[] claimArray = new String[4];
      claimArray[0] = "3MVG99OxTyEMCQ3gNp2PjkqeZKxnmAiG1xV4oHh9AKL_rSK.BoSVPGZHQukXnVjzRgSuQqGn75NL7yfkQcyy7";
      claimArray[1] = "Pierre_Delacroix@SeattleApps.com";
      claimArray[2] = "https://login.salesforce.com";
      claimArray[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
      MessageFormat claims;
      claims = new MessageFormat(claimTemplate);
      String payload = claims.format(claimArray);

      //Add the encoded claims object
      token.append(Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8")));

      //Load the private key from a keystore
      KeyStore keystore = KeyStore.getInstance("JKS");
      keystore.load(new FileInputStream("./path/to/keystore.jks"), "keystorepassword".toCharArray());
      PrivateKey privateKey = (PrivateKey) keystore.getKey("certalias", "privatekeypassword".toCharArray());

      //Sign the JWT Header + "." + JWT Claims Object
      Signature signature = Signature.getInstance("SHA256withRSA");
      signature.initSign(privateKey);
      signature.update(token.toString().getBytes("UTF-8"));
      String signedPayload = Base64.encodeBase64URLSafeString(signature.sign());

      //Separate with a period
      token.append(".");

      //Add the encoded signature
      token.append(signedPayload);

      System.out.println(token.toString());

    } catch (Exception e) {
        e.printStackTrace();
    }

  }

}

Using a JWT Bearer Token

JWT bearer tokens should be POSTed to the token endpoint at https://login.salesforce.com/services/oauth2/token or https://test.salesforce.com/services/oauth2/token.

When POSTed, the following parameters are required:
  • grant_type: urn:ietf:params:oauth:grant-type:jwt-bearer.
  • assertion: The JWT bearer token, base64url-encoded.
Additional standard parameters:
  • format: Format of the response may be specified as in an OAuth flow, using the token parameter, or an HTTP Accepts header.
  • scope: Scope is not supported in the flow. The value for this parameter is the combination of scopes from previous approvals.
Here is a sample token request:
POST /services/oauth2/token HTTP/1.1
Host: login.example.com
Content-Type: application/x-www-form-urlencoded

grant_type= urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=PHNhbWxwOl...[omitted for brevity]...ZT

Server Validates the Token

After the request is verified, Salesforce sends a response to the client. Token responses for the OAuth 2.0 JWT bearer token flow follow the same format as authorization_code flows, although no refresh_token is ever issued. A JWT OAuth 2.0 bearer assertion request looks at all the previous approvals for the user that include a refresh_token. If matching approvals are found, the values of the approved scopes are combined and an access_token is issued. If no previous approvals included a refresh_token, no approved scopes are available, and the request fails as unauthorized.

Errors

If there is an error in processing the JWT bearer token, the server replies with a standard OAuth error response, including an error and an error description containing additional information regarding the reasons the token was considered invalid. Here is a sample error response:
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
{
  "error":"invalid_grant",
  "error_description":"Audience validation failed"
}
© Copyright 2000–2013 salesforce.com, inc. All rights reserved.
Various trademarks held by their respective owners.