Development, Integration

[ART-012] JWT Bearer Flow


JWT Bearer Flow is a server to server authentication method that enables one server to authenticate in Salesforce in a secured way.


Generating certificates

Certificate is a secured way to prove the identity of a calling server and allow it to access protected information. There is no clear credentials (login/password) going back and forth between servers like in the username-password flow. The calling server holds a private key that is used to get a JWT (JSON Web Token) signed with the RS256 algorithm and RSA keys.

Step 1

I’ve used the official documentation and will recap all necessary steps to get successful without pain. The following instructions are based on PC Windows 10, latest GitBash and Salesforce Developer Edition.

Source: https://developer.salesforce.com/docs/atlas.enus.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_key_and_cert.htm

#Generate a private key named server.key
openssl genrsa -des3 -passout pass:SomePassword -out server.pass.key 2048

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

#Remove server.pass.key
rm server.pass.key

#Generate a certificate signing request using the server.key file
#Store the certificate signing request in a file called server.csr
 
openssl req -new -key server.key -out server.csr

#Generate a self-signed digital certificate from the server.key and
#server.csr files. Store the certificate in a file called server.crt
#The following command will prompt to enter some information
#I haven't used passphrase for this example

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

Step 2

Now it’s time to open your Salesforce Developer Edition instance and create a new Connected App.

SettingValue
SettingValue
Connected App NameJWT Integration
API NameJWTIntegration
Contact Emailintegration@yourmail.com
Enable OAuth SettingsChecked
Use digital signaturesChecked
upload the certificateselect the server.crt we have generated
Callback URLhttps:// <login or test or mydomain> /services/oauth2/success
scopeAccess and manage your data (api) , Perform requests on your behalf at any time (refresh_token,offline_access)
run asChoose an integration user

Save the new Connected App and wait a few minutes (2-10mn), and then copy the generated consumer key that will be used in next steps.

Step 3

Click on Manage and then edit policies and make sure you have the following options :

  • Admin approved users are pre-authorized
  • Enforce IP restrictions

Then Click on manage profile and Select System Administratror and whatever profile you need.

Step 4

On your brower, call the Autorization endpoint (“success” and not “token” on redirect)

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

Step 5

Write a header file named header.txt:

{
  "alg": "RS256"
}

We will use the JWT signing algorithm RS256.

Step 6

Write a payload file named payload.txt, the exp will be replaced on the fly, login or test as audience:

{
  "iss": "<your consumer key>",
  "sub": "<username>",
  "aud": "https://<login or test>.salesforce.com",
  "exp": "1605623956"
}

For scratch org, set the audience to https://test.salesforce.com

Step 7

I’ve written a little shell script to help generate the JWT assertion, you can grab it on my github:

https://github.com/sutha2k/jwtBearer/releases/tag/v1.0

Before launching it, make sure you have set the right permissions :

chmod u+x generateJWT.sh

Launch the script with the header file, the payload file, the expiration time from now in seconds and the private key:

./generateJWT.sh header.txt payload.txt 1000 server.key

It will return an assertion that will start with

eyJhbGciOiJSUzI1NiJ9

Step 8

POST now the assertion in the token endpoint:

curl --location --request POST 'https://<login or test>.salesforce.com/services/oauth2/token?grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<assertion>' --header 'Content-Type: application/x-www-form-urlencoded'

It will return a response like this:

{"access_token":"<access token>",
"scope":"api","instance_url":"https://<login or test or domain>.salesforce.com",
"id":"https://<login or test>.salesforce.com/id/<ID1>/<ID2>",
"token_type":"Bearer"}

Step 9

Get the access_token/instance_url from the response (very important) and now you can make authenticated call to Salesforce resources:

curl --location --request GET '<instance_url>/services/data/v50.0/limits' --header 'Authorization: Bearer <access_token>'

Conclusion

Securing access to private resources is mandatory while setting up integration between servers, this flow is one the most recommended. This article aims to give you some insight and basis to start playing with JWT Bearer Flow and Salesforce and my goal was to demystify it by a simple working example. There are more advanced aspect like refresh token handling that I haven’t covered but there are quite good articles around the web, so just google it 😉

Hope you enjoy reading this article, see you soon for the next one ...

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.