Set up the JWT bearer OAuth flow for Salesforce
Refer to Salesforce public documentation for enabling server-to-server integration with OAuth 2.0 JSON Web Tokens
Creating a cert/key pair of PEM files
Create a cert/key pair of PEM files
openssl req -newkey rsa:4096 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
Creating a Salesforce connected app with JWT
Log in to Salesforce
and click the settings gear at top right and select Setup. On the left, navigate to App Manager. (Platform Tools > Apps > App Manager)
Choose New Connection App.
Provide an app name, let the rest be auto filled.
Check the box for Enable OAuth Settings.
Set a callback URL. It won’t be used for JWT, so you can use https://localhost.
Check the box for Use Digital Signatures.
Upload the cert.pem file created earlier.
Add the required permissions:
Manage user data via APIs (api).
Access custom permissions (custom_permissions).
Access the identity URL service (id, profile, email, address, phone).
Access unique user identifiers (openid).
Perform requests at any time (refresh_token, offline_access).
Check the box for Issue JSON Web Token (JWT)-based access tokens for named users.
Choose Save.
Choose Continue.
Choose Manage Consumer Details.
Copy the consumer key (client id).
Copy the consumer secret (client secret).
Click Cancel.
Generating a JSON Web Token (JWT)
Convert key pair into pkcs12 (set an export password when prompted).
openssl pkcs12 -export -in cert.pem -inkey key.pem -name jwtcert > jwtcert.p12
Create a Java keystore from pkcs12 (set a destination keystore password when prompted, and provide previous export password for source keystore password).
keytool -importkeystore -srckeystore jwtcert.p12 -destkeystore keystore.jks -srcstoretype pkcs12 -alias jwtcert
Confirm keystore.jks includes jwtcert alias (enter previous destination keystore password when prompted).
keytool -keystore keystore.jks -list
Use the Java class JWTExample provided in Salesforce documentation to generate the signed token.
Edit the values in claimArray as necessary:
claimArray[0] = client id
claimArray[1] = salesforce user id
claimArray[2] = salesforce login url
claimArray[4] = expiration date in millis since epoch. 3660624000000 is 2085-12-31.
Replace path/to/keystore with correct path to your keystore.jks.
Replace keystorepassword with the destination keystore password you entered
Replace privatekeypassword with the source keystore password you entered
Compile the code. The code depends on the Apache Commons Codec
for base64 encoding. javac -classpath ".:./commons-codec-1.16.1.jar" JWTExample.java
Run the code.
java -classpath ".:commons-codec-1.16.1.jar" JWTExample
Once the connected app and JWT are created, still the user needs to be authorized for the app. See step 3 in https://mannharleen.github.io/2020-03-03-salesforce-jwt/ for two approaches.
With the above steps completed, this should output a JSON Web Token (JWT) which can be used to obtain access tokens from Salesforce.
Example input:
export password for pkcs12: awsglue destination keystore password for jks: awsglue source keystore password for jks: awsglue claimArray[0] = “
client-id
”; claimArray[1] = “my@email.com”; claimArray[2] = "https://login.salesforce.com“; claimArray[3] = "3660624000000"; path to keystore: ./keystore.jks keystore password: awsglue privatekey password: awsglue
Example output:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
signature
Useful links:
https://www.base64encode.org/
https://jwt.io/
https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_jwt_flow.htm
JWTExample.java:
import org.apache.commons.codec.binary.Base64; import java.io.*; import java.security.*; import java.text.MessageFormat; public class JWTExample { public static void main(String[] args) { String header = "{\"alg\":\"RS256\"}"; String claimTemplate = "'{'\"iss\": \"{0}\", \"sub\": \"{1}\", \"aud\": \"{2}\", \"exp\": \"{3}\"'}'"; try { StringBuffer token = new StringBuffer(); //Encode the JWT Header and add it to our string to sign token.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8"))); //Separate with a period token.append("."); //Create the JWT Claims Object String[] claimArray = new String[5]; claimArray[0] = "
value
"; claimArray[1] = "my@email.com"; claimArray[2] = "https://login.salesforce.com"; claimArray[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300); MessageFormat claims; claims = new MessageFormat(claimTemplate); String payload = claims.format(claimArray); //Add the encoded claims object token.append(Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8"))); //Load the private key from a keystore KeyStore keystore = KeyStore.getInstance("JKS"); keystore.load(new FileInputStream("./keystore.jks"), "awsglue".toCharArray()); PrivateKey privateKey = (PrivateKey) keystore.getKey("jwtcert", "awsglue".toCharArray()); //Sign the JWT Header + "." + JWT Claims Object Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(privateKey); signature.update(token.toString().getBytes("UTF-8")); String signedPayload = Base64.encodeBase64URLSafeString(signature.sign()); //Separate with a period token.append("."); //Add the encoded signature token.append(signedPayload); System.out.println(token.toString()); } catch (Exception e) { e.printStackTrace(); } } }