[SalesForce] JWT, Cyrpto.Sign and EncodingUtil.base64Encode

I'm writing my own class to create a JWT.

Using the JSONGenerator I am creating the header and payload, base64 encoding these with EncodingUtils. I am then creating a blob from these to sign and use in the signature.

 Blob input = Blob.valueOf(accessToken);

 String key = 'myKey';

 Blob privatekey = EncodingUtil.base64Decode(key);

 Blob signature = Crypto.Sign('RSA-SHA256', input, privatekey);

I then take that Blob result and append it to my string representation of a jwt by once again base64encoding the blob.

However the results I get cannot be verified as a valid JWT.

Using JWT.io i can see the differences in the valid and invalid token generated through my mechanism and through the website using the correct public and private keys. The difference is that in the signature section of my jwt the symbols are different. Using my mechanism underscores are represented as forward slashes and dashes and pluses

etc

BAD JWT – PC6+ZVxgtK/hm

GOOD JWT – PC6-ZVxgtK_hm

Deos anyone have any idea why this would be? If i manually change the symbols to the correct one i can validate my JWT and everything is fine.

Best Answer

As JWT is meant to be url-safe, the 62nd and 63rd characters used in Base64 encoding (+ and /, respectively) which are not url-safe must be replaced with characters that are url safe.

+ is mapped to -, and / is mapped to _

This is known as "Base64url" encoding, and is mandatory for JWT (described in the relevant IETF RFC)

Salesforce doesn't provide a built-in base64urlencode/decode method. If you're using the JWT class, I don't think you need to worry about this.

If you're rolling your own, the simple method is to simply base64encode and then use the String class's replaceAll() method to substitute the + and / characters.