Salesforce Token Exchange Flow

I’ve spent some time with the new token exchange flow in Salesforce. The flow allows you to write and configure an Apex handler in Salesforce that can validate an incoming token (say an access_token, JWT or proprietary token) from another Identity Provider (think Okta, Auth0 or any custom implementation) in Salesforce and return a Salesforce access token that can be used towards Salesforce for API access. This can simplify the integration scenario for micro services or other apps as access can be granted based on an already proved identity. The returned Salesforce access token is then used for API access as the Apex handler also maps the incoming token to a user in Salesforce – the user may optionally be created on the fly.

I captured my findings, wrote instructions on how to implement wrote an example implementation in a Github repo.

As an interesting aside, the metadata type for the OAuth Token Exchange Handler is not yet supported with the “new” source format so it has to be deployed with the old school metadata API and format (still using the CLI though).

Export private key from Salesforce in Java Keystore format and convert to PEM format

Today I needed to use the JWT flow to get an access token from Salesforce to use the Salesforce API in a server to server scenario. To do that you need a private key (usually in PEM format) for the client and the corresponding public key in a keystore on the Salesforce side. Being lazy I simply generated a public / private key pair in Salesforce with an exportable private key and exported the keystore.

Since Salesforce exports the keystore in Java Keystore Format (JKS) I need to work with the Java keytool and openssl to export the private key. Below are the steps. The landing_site_pk alias below is the same of the private key entry in the keystore and the API name of the keystore in Salesforce and Passw0rd is the password specified when exporting the keystore. Adjust as needed.

$ keytool -importkeystore -srckeystore ./00D090000046d3F.jks -srcstorepass Passw0rd -srcalias landing_site_pk -destalias landing_site_pk -destkeystore ./00D090000046d3F.p12 -deststoretype PKCS12 -deststorepass Passw0rd -destkeypass Passw0rd
Importing keystore ./00D090000046d3F.jks to ./00D090000046d3F.p12...

$ openssl pkcs12 -in ./00D090000046d3F.p12 -nodes -nocerts -out 00D090000046d3F.pem
Enter Import Password:
MAC verified OK

$ cat 00D090000046d3F.pem
Bag Attributes
friendlyName: landing_site_pk
localKeyID: 54 69 6D 65 20 31 36 30 36 33 39 30 30 35 36 38 30 38
Key Attributes:
-----BEGIN PRIVATE KEY-----
MIIEuwIBA....bTe+Hzyz
-----END PRIVATE KEY-----

2 legged vs 3 legged OAuth

Had a question come in from a customer that centered around understanding the difference between 2 legged and 3 legged OAuth so I thought I would write a little about it. I short 2 legged and 3 legged OAuth refers to the number of players involved in the OAuth dance but let’s explain each.

3 legged OAuth is used when you as a user wants to allow an application (i.e. Salesforce) to access a service (i.e. Azure) on your behalf without the application (Salesforce knowing your credentials for the service (Azure). This is accomplished by me (the user) being redirected by the application (Salesforce) to the service (Azure) where I log in directly, I obtain a code that the application (Salesforce) can use to obtain an access token for the service (Azure) out of band (i.e. the application contacts the service directly). Key is that I the user am involved because I need to authenticate to the service (Azure) and the application is afterwards able to impersonate me towards the service.

2 legged OAuth is used when an application needs to access a service using a service account (e.g. an App Registration as it’s called in Azure). The key here is that the application has all the information it needs to authenticate to the service. In 2 legged OAuth the application makes a single call to the service to basically exchange credentials (username/password, client_id/client_secret, Json Web Token (JWT)) for an access token. As an aside there is usually no way to get a refresh token issued in a 2 legged OAuth dance which is fair as the application could just perform the 2 legged OAuth dance again to get a new access token hence no need for a refresh token.

Looking back towards Salesforce and Named Credentials which is the way we recommend customers manage credentials for accessing services outside Salesforce. In Named Credentials you can use 3 legged OAuth if you selected “OAuth 2.0” for “Authentication Protocol” and 2 legged OAuth if you select “JWT” for “Authentication Protocol”.

Generate a Java Keystore (JKS) which is importable in Salesforce

Salesforce only supports the Java Keystore (JKS) format for importing private/public key pairs (with certificate) into a Salesforce org. Certificates and private/public keypairs are important when using Json Web Tokens (JWT’s) for integration using outbound flows as the JWT needs to be signed using the private key.

If working with Named Credentials for an outbound JWT token flow you need to import a private/public key into Salesforce using “Certificate and Key Management” in Setup. In the latter case you could also use a self-signed certificate generated in Salesforce.

What ever you do you need a valid keystore. Below are the commands I use to generate a private/public keypair with openssl and then use keytool (the Java keystore tool) to import into a Java keystore valid for Salesforce.

# generate private/public keypair
openssl req -newkey rsa:2048 -nodes -keyout private_key.pem -x509 -days 365 -out certificate.pem

# write certificate in binary file (some sytems need binary format)
openssl x509 -outform der -in certificate.pem -out public_key.der

# get the public key from the certificate
openssl x509 -in certificate.pem -pubkey > public_key.pem

# import certificate into Java Key Store (JKS)
# !!! Be sure to trust the certificate - otherwise it's not imported
keytool -importcert -file certificate.pem -keystore keystore.jks -alias mycertificate -storetype jks

# create a PKCS12 keystore with private/public keypair
openssl pkcs12 -inkey private_key.pem -in certificate.pem -export -out keystore.p12 -name mykey

# import keypair into Java keystore
keytool -importkeystore -destkeystore keystore.jks -srckeystore keystore.p12 -srcstoretype pkcs12 -destalias mykey -srcalias mykey

Utility to generate JWT’s for use with Salesforce

Whenever you work with Json Web Tokens (JWT’s) generating them for testing is always a hassle as they usually are required to expire quite quickly (like in the order of minutes). To make that easier I wrote a small utility in node.js to generate JWT’s compatible with the Salesforce OAuth 2.0 JWT Bearer Flow.

Code is on Github at https://github.com/lekkimworld/salesforce-jwt-generator

YMMV!

Using the inbound OAuth 2.0 JWT Bearer Flow in Salesforce

If working with JWT’s for use with the inbound OAuth 2.0 JWT Bearer Token Flow you need to import a public key and a certificate to validate the signature of the JWT when calling into Salesforce. This is done on the Connected App and the import supports binary DER-format and the plain text PEM-format.

Once you’ve created your Connected App, check “Enable OAuth Settings” and under “Use digital signatures” import the certificate (PEM or DER format) to use to validate the signature of the JWT.

Using the actual flow requires you set the Consumer Key as the issuer (“iss”), the username of the user to act as, as the subject (“sub”) and the login-url as the audience (“aud”). The login-url will be https://login.salesforce.com, https://test.salesforce.com or a community url.

To make it easier to work with and test I’ve created a node.js console app that allows you to generate JWT’s that are compatible with Salesforce. The code is on Github at https://github.com/lekkimworld/salesforce-jwt-generator.

Exchanging the JWT for an access_token is as below setting the grant_type to urn:ietf:params:oauth:grant-type:jwt-bearer and specifying the signed JWT using the assertion-parameter:

POST /services/oauth2/token HTTP/1.1
 Host: login.salesforce.com
 Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYX...VtbyJ9.AjsbapI5XTeLpPLZJk2_a2PnpAV0iUOT6xxgUWZsjYBeH9FcWHjiS6DMw1xuNyOcHNxY6hTAp1_D6HPDY4i0hgOFzb0YUaaWf9MoplpNknsGhYZ0SOHX2OSIfFVZ7KdPx1_BudRSi3VDNt33EZhf3cm07rMSJu-DOzHP1BSJE4HXALusEV3WgdSyijUce4daF3PVANI8w-yGAhFkdO8RCrCAufaZVxtTI1ZmnXeDRxbULQZ9hnn0vtgYHaMcgTK41ZGay3UN7XVa-FERG4WcdnvylPAhnalgSFlCDX3UHvUdn-wxYX0pSPw41R2rjPUDCWBiEV8ULzEiWQrBpyqkww

Generating JWT’s for Azure in Apex

Lately I’ve been playing around with Azure and integrating Salesforce and Azure. One of the integration patterns calls for using Json Web Tokens (JWT) that you can the exchange for an access token in Azure. There is a catch however…

Since Azure requires that the thumbprint of the certificate be added to the header of the JWT (using the key “x5t”) we cannot use the built in support for JWT in Named Credentials as there are no provisions for custom header key/values. The JTW/JWS classes in Apex cannot be used either as we cannot customize the header there either. Building upon https://github.com/salesforceidentity/jwt I’ve created https://github.com/lekkimworld/azurejwt-apex that bridges the gap.

This allows you to build and sign a JWT that you may exchange for an access token using your tenants OAuth token endpoint v.2 in Azure. Example Apex code is like this:

// declarations (because I'm old school)
final String azureClientId = '88d888a5-0cf4-473a-b9a0-7c88e6fc888e';
final String azureTenantId = 'b34feb2b-132f-4322-af1d-c888f5d888d0';
final String azureCertThumbprint = '4rElsDFTysrbKhB0zTsrRNSxT6s=';
final String azureScopes = '5384888d-868f-442b-b1b3-8688807de914/.default';

// create JWT with certificate from keys mgmt and set the x5t in the header to the 
// thumbprint of the cert as expected by Azure
AzureJWT jwt = new AzureJWT();
jwt.cert = 'JWT_Callout_Certificate';
jwt.iss = azureClientId;
jwt.sub = azureClientId;
jwt.aud = 'https://login.microsoftonline.com/' + azureTenantId + '/oauth2/v2.0/token';
jwt.x5t = azureCertThumbprint;

// invoke the flow and obtain an access_token
final String access_token = AzureJWTBearerFlow.getAccessToken(azureClientId, azureTenantId, azureScopes, jwt);

// use the access token against a Function App in Azure
HttpRequest req = new HttpRequest();
req.setEndpoint('https://foo-functions-demo.azurewebsites.net/api/MyFunction?name=Salesforce');
req.setMethod('GET');
req.setHeader('Authorization', 'Bearer ' + access_token);
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());

In the https://github.com/lekkimworld/azurejwt-apex Github repo you will find the two Apex classes from the above example together with the example code.

The certificate thumbprint (bold above) isn’t the regular SHA-1 thumbprint but is a special hexdump/base64 encoded edition. To make it even more interesting the thumbprint displayed in Azure Portal is not the thumbprint we need. The thumbprint/hash may be computed this like (gleaned from https://stackoverflow.com/a/52625165):

echo $(openssl x509 -in yourcert.pem -fingerprint -noout) | sed 's/SHA1 Fingerprint=//g' | sed 's/://g' | xxd -r -ps | base64