Named credential JWT is not appearing in Authorization header in callout

authorizationcalloutjwtnamedcredentials

I've configured a Named Credential to use the JWT authentication protocol (not JWT Token Exchange), but when the component makes a call to my service using the named credential, I don't get the JWT as an Authorization header. I checked all the headers, and don't see an "Authorization" header at all.

When I change the authentication type to basic or JWT Token Exchange, then it works, sending the values I expect.

Should there be a JWT in the Authorization header?

Do I have my issuer and audience set up correctly? When I experimented with JWT token exchange, it seemed picky about those.

Certificate: (empty)

Identity Type: Named Principal

Authentication Protocol: JWT

Issuer: <the host name of my Salesforce instance>.lightning.force.com

Named Principal Subject: <my user name>

Audiences: https://<the base URL of the remote server>

Token Valid for: 10 Seconds

JWT Signing Certificate: My_Sample

Generate Authorization Header: checked

Allow Merge Fields in HTTP Header: checked

Allow Merge Fields in HTTP Body: checked

Outbound Network Connection: blank

My Apex code (actually written by someone else a long time ago), which works for Basic Authentication

      HttpRequest request = new HttpRequest();
      String statusApi = 'callout:my_named_connection/api/status';

      request.setEndpoint(ApiProxy.appendUrlParams(statusApi, request));
      request.setMethod('POST');
      request.setHeader('Content-Type', 'application/json');
      request.setHeader('Content-Length', String.valueof(body.length()));
      request.setBody(body);  

      request.setTimeout(10000);
      HttpResponse  response = http.send(request);

Best Answer

You don't get a "JWT" header, because JWT typically (and in the case of Salesforce) uses the "Authorization" header with the Bearer scheme. The Authorization header contains all the JWT information needed. There is no "JWT" in the "Authorization" header itself, because a) it's Base64 encoded and b) does not state "JWT" as such in its three constituents.

Take the HTTP request generated by Salesforce, copy the long string after "Bearer" and get it decrypted and split up into its parts for example here:

https://jwt.io/

Explanations of the elements can be found in the relevant RFCs 7515 and 7519.

Decoding the bearer and finding its elements in the spec helps answering the other questions.

E.g. you will have noticed that Salesforce's "Issuer" becomes "iss" in the (decoded) Bearer token; one RFC uses "joe" as an example for a possible value, but it can be any "StringOrURI". You could provide an URI (which should be "https://...my.salesforce.com", not "... lightning..."), but I'd suggest a Salesforce user name. This is "OPTIONAL"; I don't know your endpoint provider, but if you are not told explicitly otherwise, the success of the communication should not depend on it.

Salesforce's "Audience" is "who or what the token is intended for". (The Bearer token has "aud" and this is only described by RFC 7519.) Although also optional, it is more often decisive. It is also "StringOrURI". https://<the base URL of the remote server> looks alright to me.

Finally, the decoded Bearer token has typ: "JWT" - the closest you can get to what you were looking for.

I'd uncheck the two check boxes for "Merge Fields". At least the code you provided doesn't show any use of merge fields.

Related Topic