Table of Contents [expand]
Last updated April 30, 2026
Heroku AppLink supports JWT (JSON Web Token) authorization using JWT Bearer Token Flow for headless authentication in CI/CD pipelines and automated workflows. JWT authorization eliminates the need for interactive browser-based OAuth flows. Authorizations with AppLink require a Salesforce external client app that’s configured with certificate-based authentication.
For more information on Heroku AppLink authorizations, see Working with Heroku AppLink.
As of the Salesforce Spring ’26 release, you can no longer create new connected apps in Salesforce. We’re deprecating using connected apps with Heroku AppLink, and replacing them with external client apps. From now on, create and use external client apps instead of connected apps with your Heroku AppLink integrations. If you have existing connected apps in your Salesforce org, you can still reference them in the API spec file or migrate them to external client apps.
Prerequisites
Before authorizing a user, you must:
Generate an RSA Key Pair
You need an RSA private key and self-signed certificate to use for the authorization command. To generate, run:
openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes
You also need a public key to upload for your external client app:
openssl x509 -pubkey -noout -in server.crt > server.pub
Create an External Client App
Next, create and configure an external client app in Salesforce. Follow the Salesforce documentation to:
- Create an external client app
- Select
Enable OAuth Settings - Select
Use Digital Signaturesand upload yourserver.crtcertificate - Set the
Callback URLtohttp://localhost:1717/OauthRedirect - Select the OAuth scopes for your external client app. At minimum, set the
apiandrefresh_tokenscopes.
Pre-Authorize Users
Then, pre-authorize the users who can use the external client app. You must add the user you want to authorize AppLink with. Follow the Salesforce documentation to:
- Select
Admin approved users are pre-authorizedin thePermitted Usersdropdown. - Select specific profiles or permission sets to give access to your external client app.
Authorize Users on Heroku AppLink
You need the following to authorize a user:
client-id: The consumer key from your external client app. This client ID must match the key used to generate the JWT private key.jwt-key-file: The RSA private key you previously generated.username: Must be a user in the org and who has been pre-authorized for the external client app.
To authorize a Salesforce user via JWT, run the command:
$ heroku salesforce:authorizations:jwt:add org_jwt --addon applink-simple-60625 -a example-app --client-id 3MVG9N7GK6... --jwt-key-file jwt/server.key --username test-user@example.com --login https://test.salesforce.com
Adding credentials for test-user@example.com to example-app as org_jwt... Connected
To authorize a Data Cloud user via JWT, run the command:
$ heroku datacloud:authorizations:jwt:add dc_jwt --addon applink-simple-60625 -a example-app --client-id 3MVG9N7GK6... --jwt-key-file jwt/server.key --username test-user@example.com --login https://test.salesforce.com
Adding credentials for test-user@example.com to example-app as dc_jwt... Connected
Use the Authorization In Your App
After authorizing, your app can retrieve credentials using the AppLink SDKs. For example with the Node.js AppLink SDK for Salesforce:
const Applink = require('@heroku/applink');
const applink = new Applink();
// Retrieve authorization by developer name
const auth = await applink.getAuthorization('my-auth');
console.log('Access Token:', auth.access_token);
console.log('Instance URL:', auth.instance_url);
// Or retrieve by alias
const authByAlias = await applink.getAuthorizationByAlias('applink:my-auth');
CI/CD Integration Examples
Here are some examples of using your authorizations in CI/CD integrations.
GitHub Actions
name: Deploy with AppLink JWT
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Heroku CLI
run: |
curl https://cli-assets.heroku.com/install.sh | sh
heroku plugins:install @heroku-cli/plugin-applink
- name: Add JWT Authorization
env:
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
JWT_PRIVATE_KEY: ${{ secrets.JWT_PRIVATE_KEY }}
SF_CLIENT_ID: ${{ secrets.SF_CLIENT_ID }}
SF_USERNAME: ${{ secrets.SF_USERNAME }}
run: |
echo "$JWT_PRIVATE_KEY" > /tmp/jwt.key
heroku salesforce:authorizations:jwt:add ci-auth \
--app my-app \
--client-id $SF_CLIENT_ID \
--jwt-key-file /tmp/jwt.key \
--username $SF_USERNAME
rm /tmp/jwt.key
- name: Deploy to Heroku
run: git push heroku main
CircleCI
version: 2.1
jobs:
deploy:
docker:
- image: cimg/base:stable
steps:
- checkout
- run:
name: Setup Heroku
command: |
curl https://cli-assets.heroku.com/install.sh | sh
heroku plugins:install @heroku-cli/plugin-applink
- run:
name: Add JWT Authorization
command: |
echo "$JWT_PRIVATE_KEY" > /tmp/jwt.key
heroku salesforce:authorizations:jwt:add ci-auth \
--app $HEROKU_APP_NAME \
--client-id $SF_CLIENT_ID \
--jwt-key-file /tmp/jwt.key \
--username $SF_USERNAME
rm /tmp/jwt.key
workflows:
deploy:
jobs:
- deploy:
context: production
Security Best Practices
Here are some best practices to keep in mind:
- Key Rotation: Rotate JWT key pairs regularly, for example, every 90 days.
- Key Storage: Store private keys securely in secret managers such as GitHub Secrets, AWS Secrets Manager, etc.
- Access Control: Use dedicated service accounts with minimal required permissions.
- Audit Logging: Monitor authorization usage in Salesforce Setup > Login History.
- Key Protection: Never commit private keys to version control (add
*.keyto.gitignore).