2

How to generate signed JWT token in Apex using JWK keyset. I know Auth.JWS can be used to generate bearer token.

JWS(jwt, certDevName)

but it uses certificate to generate token.

My requrement is generate using JWK keyset.

1
  • Not possible in pure Apex. You might be able to do it in Apex + crypto library in JS. A JWK in JWKS rarely contains a private key for signing JWT (required if you're generating one) but it's certainly possible. If it does, you can manually extract it, convert it into appropriate format and import it into Certificates and Keys.
    – identigral
    Jan 25, 2021 at 16:09

1 Answer 1

0

Since you're using a standard that Salesforce hasn't adopted (or probably more accurately, hasn't provided built-in tools to handle in Apex) you'll need to do it the hard/long way.

Provided that:

  • You can find a key of type "sig"
  • and extract it
  • and it's for one of the algroithms supported by the Crypto class
    • for the sign() method: RSA, RSA-SHA1, RSA-SHA256, RSA-SHA384, RSA-SHA512, ECDSA-SHA256, ECDSA-SHA384, and ECDSA-SHA512

You can just go through the steps to generate the JWT. The code for that isn't too bad at all

String alg = 'RS256';
String iss = 'MyConnectedAppClientId';
String aud = 'https://test.salesforce.com';
String sub = '[email protected]';
Long exp = DateTime.now().addMinutes(5).getTime();

String jwtHeader = '{"typ":"JWT","alg":"RS256"}';
String jwtPayload = String.format('{"iss":"{0}","sub":"{1}","aud":"{2}","exp":{3}}', new List<Object>{iss, sub, aud, exp});

String jwtClearPart = String.format('{0}.{1}', new List<Object>{
    // Salesforce doesn't give us a method for base64url encoding, so we need to do that ourselves
    System.EncodingUtil.base64Encode(Blob.valueOf(jwtHeader)).replace('+', '-').replace('/', '_'),
    System.EncodingUtil.base64Encode(Blob.valueOf(jwtPayload)).replace('+', '-').replace('/', '_')
});

// Time to use the Crypto class to generate the signature
// I assume that you'll be able to get the key to use for the signature fairly easily using
//   something like JSON.deserializeUntyped()
Blob jwtSig = Crypto.sign('RSA-SHA256', Blob.valueOf(jwtClearPart), key);

String jwt = String.format('{0}.{1}', new List<Object>{jwtClearPart, jwtSig.toString()});
4
  • Thanks Derek, But my jwk key set does not have key, Here are the fields in standard jwk key set ( generated using mkjwk.org) { "p": "...", "kty": "RSA", "q": "...", "d": "...", "e": "AQAB", "use": "sig", "kid": "...", "qi": "...", "dp": "...", "alg": "RS256", "dq": "...", "n": "..." }
    – sare
    Jan 26, 2021 at 0:05
  • The Crypto.sign needs privatekey in pkcs8 format, now who to get is from my jwks
    – sare
    Jan 26, 2021 at 0:15
  • Your jwtSig is in incorrect format .. it should be .. public static Blob sign(String algorithmName, Blob input, Blob privateKey)
    – compski
    Mar 9, 2023 at 10:01
  • @compski Issue has been fixed.
    – Derek F
    Apr 10, 2023 at 13:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .