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.
#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.

Setting | Value |
---|---|
Setting | Value |
Connected App Name | JWT Integration |
API Name | JWTIntegration |
Contact Email | integration@yourmail.com |
Enable OAuth Settings | Checked |
Use digital signatures | Checked |
upload the certificate | select the server.crt we have generated |
Callback URL | https:// <login or test or mydomain> /services/oauth2/success |
scope | Access and manage your data (api) , Perform requests on your behalf at any time (refresh_token,offline_access) |
run as | Choose 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 ...