Salesforce OAuth 2.0 JWT Bearer flow
Amit Chaudhary

Amit Chaudhary

Amit Chaudhary is Salesforce Application & System Architect and working on Salesforce Platform since 2010. He is Salesforce MVP since 2017 and have 17 Salesforce Certificates. He is a active blogger and founder of Apex Hours.

Salesforce OAuth 2.0 JWT Bearer flow

In this post we are going to learn how to implement the Salesforce OAuth 2.0 JWT Bearer flow in Salesforce. OAuth 2.0 JWT Bearer flow is used for server to server integration scenarios. This flow uses a certificate to sign the JWT request and doesn’t require explicit user interaction. However, this flow does require prior approval of the client app.

What is JWT Bearer flow?

Secure server-to-server integration without real time user involvement. Client specifies user in a JSON web token (JWT) or SAML format XML assertion and proves its own identity by appending a signature. JWT Bearer token flow is Ideal for application which access sfdc only through API as there is no UI involved. For example ETL tools or middleware.

This flow uses a certificate to sign the JWT request and doesn’t require explicit user interaction. However, this flow does require prior approval of the client app.

JWT Structure

When we talk about JSON Web Token, it is consist of 3 parts

  1. Headers – Which contains the algorithm which will be used to sign the request {"alg":"RS256"}
  2. Payload – This contains claims information which is an object containing information about user and additional data. Claims are set using parameters- {"Iss,aud,sub,exp"}
  3. Signature – Signature consists of 3 parts and the structure is given below
<headerbase64encodedurl>.<claimsbase64encodedclaims>.<signature(uses algorithm like RS 256)>

JWT flow example in Salesforce

Lets start with JWT uses. In this example we will how we call another Salesforce org API using JWT flow in Salesforce.

Step 1) Creating private key and X509 certificate

First step using OAuth JWT Bearer Token flow is creating the Certificate. To create the certificate you need open SSL. Download it you are using window.

Step 1.1) Set OPENSSL_CONF path

set OPENSSL_CONF=C:\openssl\share\openssl.cnf 

Step 1.2) Generate an RSA private key

Execute below command and in output it will return your Server.pass.Key file. Server.Key is our private key.

openssl genrsa -des3 -passout pass:x -out server.pass.key 2048

Step 1.3) Create a key file from the server.pass.key file

Execute below command and in output it will return your Server.Key file. Server.Key is our RSA private key.

openssl rsa -passin pass:x -in server.pass.key -out server.key

Step 1.4) Request and generate the certificate

Below command will request for certificate.

openssl req -new -key server.key -out server.csr

Once you will execute above command it will ask you some question and information

  • Country Name : Provide any value for example : US
  • State or province Name [Some-State]: Georgia
  • Locality Name( eg. city)[] : Alpharetta
  • Organization Name (eg. company) : Apex Hours
  • Organization Unit Name : AH
  • Comman Name [] : You can keep it blank
  • Email Address [] : [email protected]

Step 1.5) Generate the SSL certificate

openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt

Step 2: Create JWT Connected App in Salesforce

Now you have certificate file (server.crt) with you. It time to create a connected app in Salesforce.

Step 2.1) Creating connected app in Salesforce

Go to Setup -> Search for connected app -> then click on New (connected app). Then provide below details.

  1. Fill Name and Email
  2. Click on “Enable OAuth Setting
  3. Call back URL “http://localhost:1717/OauthRedirect
  4. Click on “Use Digital Signature” and upload the certificate created in Step 1.5.
  5. Select the following OAuth Scopes
    1. Manage user data via APIs (api)
    2. Manage user data via Web browsers (web)
    3. Perform requests at any time (refresh_token, offline_access)
  6. Click on Save
Connected app for JWT FLOW.

Once you are done you will get Cliend_Id and Client_secret.

Step 2.1) Prior approval of the client app

There are different option to do that.

  • Option 1: Admin approves from connected app in Salesforce.
  • Option 2: Pre-Approve the connected app with the User-Agent OAuth Flow
  • Option 3: Run the auth:jwt:grant CLI command

Why we need this step. If you will not perform it then you will get below error while authenticate the user.

 {"error":"invalid_grant","error_description":"user hasn't approved this consumer"}

Option 1: Admin approves from connected app in Salesforce

Will use Salesforce console for this.

  1. Go to Setup -> click on Manage Apps -> Connected Apps
  2. Click ‘Edit’ against your app
  3. Click on Permitted Users and select “Admin approved users are pre-authorized
  4. Save.
  5. Now it time to provide access to profile or permission set. Go to setup -> Manage Users -> Profiles
  6. Select the profile which you want to access for example Integration profile.

Option 2: Pre-Approve the connected app with the User-Agent OAuth Flow

Copy and paste this link in the browser

https://<your instance>.salesforce.com/services/oauth2/authorize?response_type=token&client_id=<consumer key>&redirect_uri=http://localhost:1717/OauthRedirect

Login to Salesforce and authorize the connected app. Click Allow button.

Option 3: Run the auth:jwt:grant CLI command

Specify the client identifier from your connected app (also called the consumer key), the path to the private key file (server.key), and the JWT authentication username. When you authorize a Dev Hub org, set it as the default with the –setdefaultdevhubusername parameter. For example

sfdx auth:jwt:grant --clientid 04580y4051234051 \
--jwtkeyfile /Users/jdoe/JWT/server.key --username [email protected] \
--setdefaultdevhubusername --setalias my-hub-org

Step 3) Create JWT Token

Now our certificate is ready and uploaded in Salesforce connected App. It time to create a JWT token and test it out. As we discussed early we have three parameter in JWT Structure.

  • Headers
  • Payload
  • Signature

You can use https://jwt.io/ for simple testing. For that you need to provide all above values.

Headers: Algoritham & Token Type

{"alg":"RS256"}

Payload: Data

{
"Iss : "Clint_ID From Step 2.1.1",
"sub": "UserName",
"aud": "LoginURL https://login.salesforce.com",
"exp": "CurrentTimeStemp+2min"
}

 You can use different website to get timestamp. You can use unixtimestamp.com to get current value.

Signature

Now it time to pass verify signature details.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  Private Key
)

Copy Private Key value from Server.Key ( Step 1.2). Once all look good you will Signature Verified in bottom of the screen with JWT Token.

JWT Token.

Step 4) Get access_token using JWT by POSTMAN

There are different way to test our JWT flow to get access_token. For this demo we will use POSTMAN to get access_token using JWT token which we created in last step 3.

Generate JWT Token from POSTMAN.
  • Method: POST
  • URL: https://login.salesforce.com/services/oauth2/token
  • Header Param
    • grand_type : urn:ietf:params:oauth:grant-type
    • assertion : USE JWT TOKEN created in STEP 3 using jwt.io.

Congratulation now you have access_token to execute any Salesforce API. Learn more about JWT Bearer flow for our old session JWT / SAML Assertion Bearer Flows. This how complete flow will look like.

Salesforce OAuth 2.0 JWT Bearer flow

JWT Flow using Apex

So far we created the JWT flow using jwt.io app. Let see how to use the same with Salesforce Apex class. For example you want to call one salesforce org API from another Salesforce org. For that you need to import the certificate in target org and you need Java Keystore (JKS) file format.

Generate a Java Keystore (JKS) which is importable in Salesforce

Salesforce only supports the Java Keystore (JKS) format for importing private key pairs in a Salesforce org.

Convert .CRT to Salesforce Keystore JKS file

We already have sever.crt file by using our step1. Let see how we can convert the same

  1. Go to same folder where you created server.key file(By using step 1). Clone the server.key file and save as server.pem.
  2. Now execute this command : openssl pkcs12 -export -in server.crt -inkey server.pem -out testkeystore.p12
  3. Now execute keytool command to create jks file. keytool -importkeystore -srckeystore testkeystore.p12 \ -srcstoretype pkcs12 \ -destkeystore servercert.jks \ -deststoretype JKS
    1. It will ask you to create password. remember it we will it soon.
  4. Now Salesforce dont support default alias 1. So change the alias name with this command keytool -keystore /servercert.jks -changealias -alias 1 -destalias salesforcetest

Import the Java Keystore (JKS) in

Now it time to import the Certificate in Salesforce

  1. Go to setup-> Search for Certificate and Key management
  2. Then Click on Import From Keystore.
  3. Then upload the servercert.jks file and provide the password which you to create the “servercert.jks” file.

Create a Apex class to execute the JWT Flow

Here Is JWT Apex Class without named credential.

Auth.JWT jwt = new Auth.JWT();
jwt.setSub('[email protected]');
jwt.setAud('https://login.salesforce.com'); 
jwt.setIss('connected app client id');

//Create the object that signs the JWT bearer token
Auth.JWS jws = new Auth.JWS(jwt,’Certificate keystore name’);
String token = jws.getCompactSerialization();
String tokenEndpoint ='https://login.salesforce.com/services/oauth2/token';

Auth.JWTBearerTokenExchange bearer = new Auth.JWTBearerTokenExchange(tokenEndpoint, jws);

//Get the access token
String accessToken = bearer.getAccessToken();
system.debug('Access Token-->'+accessToken);

APEX CODE WITHOUT NAMED CREDENTIALS

We know above class is not secure and having all securite details in apex. Which is not a best practice in Salesforce. For same we recommend use named credentials like below

JWT Named Credentials

And update your apex class like below.

String service_limits='/services/data/v48.0/sobjects/Account/listviews/';

HttpRequest req = new HttpRequest();
req.setEndpoint('callout:JWT_Demo'+service_limits);
req.setMethod('GET');

Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
System.debug(res.getstatuscode());

Salesforce OAuth 2.0 JWT Bearer flow Video

Check below recording to learn complete JWT flow in Salesforce using video.

Summary

OAuth JWT Bearer token flow is Ideal for application which access sfdc only through API as there is no UI involved. For example ETL tools or middleware. Digital certificates are required in this flow. Upload certificate (X509 ) to connected app which will be used to authenticate JSON web tokens. No refresh token is returned in this flow. So if access token expires then send request to generate access token again.

Share this article

1 Comment

  • You use JWT.io when you are requesting for access token. Is it possible that we directly upload our certificate and key in postman and get the token?

Leave a reply

Keep in Touch

Subscribe for Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 3,230 other subscribers

Search

Our Supporter

RECENT POSTS

Apex Hours

Apex Hours is one stop platform to learn Salesforce skills and technology

Join our Newsletter and get tips and tricks how to explore the salesforce for free!