I'm trying (and failing) to set up a connection between 2 Salesforce orgs.

This AITechone video How to configure Named credentials in salesforce to connect 2 Salesforce Org ? explains how to use a Named Credential and Auth Provider on the calling side and a Connected App on the called side. The Auth Provider holds a copy of the Consumer Key and Consumer Secret.

But as this approach is designated "Legacy", I would prefer to use the new External Credential mechanism (see Named Credentials and External Credentials) instead and side-step the Auth Provider part by using the "JWT Bearer Flow" and a Signing Certificate. But still failing after several hours with these log lines:

09:56:30.0 (8568705)|CALLOUT_REQUEST|[85]|System.HttpRequest[Endpoint=callout:MyNamedCredential/services/data/v56.0/..., Method=GET] 09:56:30.76
09:56:30.76 (76404970)|NAMED_CREDENTIAL_RESPONSE|NamedCallout[Named Credential Id=null, Named Credential Name=null, Status Code=0, Content-Type=null, Response Size bytes=0, Overall Callout Time ms=0, Connect Time ms=0
09:56:30.0 (77389457)|FATAL_ERROR|System.CalloutException: Unable to complete the JWT token exchange.

that conclude with this that gives little away:

Unable to complete the JWT token exchange.

If you know of a step by step recipe, or that this can't be made to work at the moment, please share.


1 Answer 1


Thanks identigral for your comment. That - the legacy setup - provided enough information for me to experiment and look harder at the "Set Up JWT Claims for OAuth 2.0" section of Create and Edit an OAuth External Credential that says:

Optionally, assign a value to these claims: iss, sub, and aud. You can make a callout without configuring iss, sub, and aud, and your JWT payload won't contain them. However, if you edit any preset claims or add custom claims, you must provide values for all three of these claims.

But adding these - iss, sub and aud - appears to be necessary for this case. So I have:

  • iss - set to the Consumer Key of the Connected App of the other SF instance
  • sub - set to the UserName of the integration user in the other SF instance
  • aud - set to https://test.salesforce.com (as I'm working in scratch orgs)

so the External Credential looks like this (note the added JWT Claims):


and the Named Credential just nominates the org URL and the External Credential:

Named Credential

With this approach - so far anyway - I have not run into the troublesome:

user hasn't approved this consumer

error, but of the various work-around posts on that subject I found this one by Greg Hacic Troubleshooting JWT Authorization the most helpful. And do check this section of the User record to see if the Connected App is approved:


Other things to watch out for:

  • The Connected App:
    • should have ... (api) and ... (refresh_token offline_access) selected in its Selected OAuth Scopes (and scopes are not allowed to be set at the Named/External Credential side)
    • should be assigned to the desired profile using its Manage button or directly in the Connected App Access section of the profile
    • should have Select Permitted Users of "Admin approved users are pre-authorized" (via the Manage and then the Policies buttons)
  • The External Credential must be associated with a permission set that the User has assigned to be able to use it via its Named Credential ("Permission Set Mappings" in the first screen shot)
  • 1
    refresh_token is not issued by JWT bearer flow. offline_access is a helper scope to enable silent refresh, also not relevant. With admin-approved access, web is not needed for acquiring the access token, might be needed for your app-specific use cases. The rest looks good.
    – identigral
    Commented Apr 1, 2023 at 14:18
  • Thanks @identigral - will remove.
    – Keith C
    Commented Apr 1, 2023 at 15:19
  • 1
    Hi @identigral, got this error without the refresh_token "Unable to complete the JWT token exchange. Error: invalid_request. Error description: refresh_token scope is required and the connected app should be installed and preauthorized.." so I've put that (and its accompanying offline_access) back in.
    – Keith C
    Commented Apr 1, 2023 at 15:35
  • Sigh. Thanks for verifying!
    – identigral
    Commented Apr 2, 2023 at 16:17
  • @KeithC Does this approach make sense for making a call back into the same org from a scheduled job (e.g. Dashboard Refresh) or would one of the others External Creds do that more easily? Commented Apr 11 at 15:51

You must log in to answer this question.

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