Server-to-Server Authentication with Salesforce

This post will help you understand how to integrate a server with the Salesforce API. We will use the OAuth 2.0 JSON Web Token (JWT) bearer flow for this use case. This authorization flow uses a private key to sign an authorization token and requires you to approve the API client (i.e., your server) in Salesforce. Once configured, no direct user interaction will be needed for your server to make API calls to Salesforce. Your custom application is referred to as a “Connected App” in Salesforce parlance.
Sometimes you want to authorize servers to access data without interactively logging in each time the servers exchange information.
Salesforce Docs
Summary Steps
- Create a key pair and certificate identifying your custom application
- Create a Connected App in Salesforce
- Pre-authorize access for “permitted users” to the Connected App
- Update a user profile to associate it with the Connected App
- Generate and sign an assertion token (JWT)
- Make an HTTP POST request to Salesforce with the assertion token to create an access token
- Salesforce will issue the access token and respond to the HTTP request
- Make HTTP requests to the Salesforce API using the access token
Create a Certificate and Private Key
We’ll use OpenSSL to create an x509 certificate and a private key for the Connected App. Run the following commands in your terminal to create key and certificate files.
# generate a private key with the correct length
openssl genrsa -out private-key.pem 3072
# generate a corresponding public key
openssl rsa -in private-key.pem -pubout -out public-key.pem
# create a self-signed certificate
openssl req -new -x509 -key private-key.pem -out cert.pem -days 360
Configure Salesforce
Create a Connected App
- Login to your Salesforce developer account as an administrator
- Enter “app manager” in the Quick Find box
- Click the item Apps -> App Manager
- Click the New Connected App button
- Enter the following:
- Connected App Name, e.g., My App
- API Name (should autocomplete to My_App, or similar)
- Contact Email
- Check “Enable OAuth Settings”
- Callback URL, e.g., http://localhost/callback (this value doesn’t really matter for this scenario, and, in fact, it’s not used, but Salesforce requires it anyway)
- Check “Use digital signatures”
- Click the Browse button to upload
cert.pem
(this is the x509 certificate you created in a previous step) - Add the following to Selected OAuth Scopes:
- Access and manage your data (api)
- Perform requests on your behalf at any time (refresh_token, offline_access)
- Click Save
- Click Continue
- Now would be a good time to Copy the Consumer Key for the connected app and save it. We’ll need it later.
Pre-authorize Access
- Enter “manage connected apps” in the Quick Find box
- Click the item Apps -> Connected Apps -> Manage Connected Apps
- Click the Edit action beside your new connected app
- Select Admin approved users are pre-authorized from Permitted Users
- Click Save
Update a User Profile
- Enter “profiles” in the Quick Find box
- Click the item Users -> Profiles
- Click Edit beside Standard Platform User
- Scroll down to Connected App Access
- Check the checkbox beside your new connected app, e.g. “A Demo App”
- Click Save
Create an Authorization Token
In our scenario, an authorization token is simply a JWT configured with the appropriate claims and signed with the private key we created in a previous step. There are many libraries available for a wide variety of programming languages that make it easier to use JWTs in your application. However, for this post, we will use an online tool to configure our JWT.
Claims
Now is a good time to collect the claims information that Salesforce expects before configuring our JWT.
- Issuer: the Salesforce connected app consumer key you copied in an earlier step
- Subject: any username with the Standard Platform User profile
- Audience: https://login.salesforce.com
- Expiration timestamp: the current time + 10 minutes, in UNIX epoch format
You can generate an expiration timestamp on Linux or macOS in your terminal with the following shell command:
# Print current time + 600 seconds
echo "$(date +%s) + 600" | bc
Encode a JWT
- Go to https://jwt.io in a new browser tab
- Scroll down to Debugger
- Select RS256 in the Algorithm dropdown
- (we will make our edits in the Decoded section)
- Confirm Header values
"alg": "RS256"
"typ": "JWT"
- Configure Payload
"iss": "<connected app consumer key>"
"sub": <salesforce username, usually in email format>
"aud": "https://login.salesforce.com"
"exp": <timestamp>
- Verify Signature
- Open the
cert.pem
file in a text editor, copy the entire text, and paste it into the first box - Open the
private-key.pem
file in a text editor, copy the entire text and paste it into the second box - Confirm that “Signature Verified” is shown at the bottom of the debugger. If you see “Invalid Signature” instead, there is a problem with your certificate or private key.
- Open the
- Copy the JWT from the Encoded section–we’ll need it in a moment.

Request Access Token
Finally, we’ll use curl to request an access token. Head back to your terminal and run the following commands.
# Set JWT environment variable to your JWT
# Example:
# $ JWT='eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIzTVZHOXN6VmEyUn...'
JWT='<paste your JWT here>'
GRANT_TYPE='urn:ietf:params:oauth:grant-type:jwt-bearer'
SFDC='https://login.salesforce.com/services/oauth2/token'
curl -d "assertion=$JWT&grant_type=$GRANT_TYPE" -X POST $SFDC
If everything is configured properly, you should receive a response like this…
{"access_token":"00D410000012VvK!AQIAQKMzbJitdk15IQEFeDf85vZdFTDUeAEl2j2FSV2wLeOwfJY9TfRQYxtqRUalEzs8.hMQspkLjVOxgq5TcXGD8VCzkHZL","scope":"api","instance_url":"https://<tenant>-dev-ed.my.salesforce.com","id":"https://login.salesforce.com/id/00D410000012VvKEAU/005410000058zUdAAI","token_type":"Bearer"}
You can now use the access token to call the Salesforce API!!!
Categories: Tech
Amazingly clear instructions, there is only one error: “iss” should be “consumer key” not “consumer secret”
Wow! Good eye, sr, and a great catch. I’ve updated and corrected the post. Thanks for letting us know!
These are great instructions, thank you!
Noticed one small typo. When using jwt.io, I had to paste the public-key.pem into first box instead of cert.pem . Using cert.pem signature showed invalid
The response includes ‘id’ token which most likely is the row id of the signed in salesforce user which later can be used with ‘id_token’ Identify URL to access additional details about the user. The question is where are you associating this user in the authorization request?. Is this retrieved from the Admin Approved Users on the Connected App?. Further when the Authorization arrives in Salesforce, the connected App retrieves the very first user from the Provisioned list and uses his user record to generate the access token?. Thank you