How to setup OAuth JWT for the OCAPI

jwt

IMPORTANT: This article is about server-to-server communication

When working with the OCAPI (Open Commerce API), you need to do some sort of authentication to prove who you are and to verify what actions you are allowed to take.

Salesforce B2C Commerce Cloud provides multiple methods for server-to-server authentication scenarios depending on the use case:

  • Basic Authentication using the API Key and the Secret
  • Basic Authentication using the API Key, Secret, Username, and User Password
  • JWT

In this article, we will focus on the one most ‘challenging?’ to set up: the JWT token.

Generating a public and private key pair

When working with JWT, we will use a signing method to verify the authenticity of the requests sent to the server. These are easy to generate, and you have complete control over how long they are valid.

Open up your favorite terminal and execute the following command in your folder of choice:

				
					openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
				
			

This command will create two files:

  • key.pem: Your private key that will be used to sign requests to the OCAPI authorization endpoint

  • cert.pem: The certificate containing the public key will be needed later when setting up the API key in AM (Account Manager).

Create a new API Key

Like always, when we set up a server-to-server connection, we need to generate an API key in the Account Manager.

Follow the instructions on the Infocenter, with a few minor changes.

  1. In the JWT field, copy and paste the entire contents of the “cert.pem” file we generated earlier (no modifications needed)

  2. Set the Token Endpoint Auth Method to private_key_jwt.

And click save!

Authenticate!

Ok, I made that title seem like this is an easy step to do. Generating the JWT might be the most challenging part as you need to be very specific, and there is a signing step with that private key mentioned before.

JWT

But let us look at the basics. A JWT has three different parts.

The header, which describes what type the JWT is and what algorithm it is using. In this case, RS256 is used.

The payload, which is the data we are trying to send to the server. To get a token back, Salesforce B2C Commerce Cloud requires the following information to be in the JWT:

  • iss (issuer): The client ID (API Key)
  • sub (subject): The client ID (API key)
  • exp (expiration time): Current time + x seconds (1 second should do it)
  • aud (audience): The Account Manager auth endpoint

The signature, which is the header and payload signed with the private key to verify that you are allowed to send it to the server.

Generating it

If you look at the above example, the contents of a JWT are far from “rocket science.” The hard part is signing it correctly, as you need to find a sound library in your programming language of choice to get it done.

As an example, I have created a postman library to get you started!

In this example, you need to set two collection variables:

  • pkey: The entire contents of the key.pem file we generated earlier

  • api_key: The API key you generated in the Account Manager

There is also a variable called pmlib: a third-party library meant to extend the capabilities of the scripting framework within Postman. In the collection, a request called “1. Download JS for Postman” downloads it in case the initial value is not working.

Since Postman does not support generating JWT tokens out-of-the-box there is a “Pre-request script” within the second call “2. Authorization (JWT)” which generates it and stores it in a collection variable used during the request.

				
					// Load third party library
eval(pm.collectionVariables.get("pmlib"));
 
// Prepare timestamp in seconds
var currentTimestamp = Math.floor(Date.now() / 1000)

// Create header and payload objects
var header = {
  "typ": "JWT",
  "alg": "RS256"
};

var payload = {
	'iss': pm.collectionVariables.get('api_key'),
	'sub': pm.collectionVariables.get('api_key'),
	'iat': currentTimestamp,
	'exp': currentTimestamp + 300, // expiry time is 30 seconds from time of creation
	'aud': 'https://account.demandware.com:443/dwsso/oauth2/access_token'
};
 
// Generate the JWT and sign it
var sJWT = pmlib.jwtSign(pm.collectionVariables.get('pkey'), payload, header);

// Store the JWT to set in the body
pm.collectionVariables.set("jwt_signed", sJWT);
				
			

Once the script is in place and all required variables are configured in the collection we can execute the request as follows:

  • A POST to https://account.demandware.com/dwsso/oauth2/access_token

  • A body containing these 3 values as a x-www-form-urlencoded type:
    • client_assertion: The signed JWT generated by the script
    • client_assertion_type: urn:ietf:params:oauth:client-assertion-type:jwt-bearer
    • grant_type: client_credentials

A big thanks to Yuriy Boev and John Boxall for helping me get to a working example! I will refer you to the Unofficial Slack thread for other scripts or languages!

Table of Contents

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

More From My Blog