[SalesForce] Using Named Credential + OpenID Connect auth provider to obtain access token with client_credentials grant

I am trying to use the Named credentials for the first time without using the named credentials directly if I call the endpoints with credentials it works perfectly fine which uses OAuth where I get the Bearer/Access token from Microsoft and use them to post the data to the external system like below

@future (callout=true)
public static void createSegmentD365(String subSegmentID) {
    String clientId = 'xxxxxxxxxxx';
    String clientSecret = 'xxxxxxxxxx';
    String tenant_id = 'xxxxxxxxxx';
    String resource = 'https://dev.cloudax.dynamics.com';

    String reqbody = 'grant_type=client_credentials&client_id='+clientId+'&client_secret='+clientSecret+'&tenant_id='+tenant_id+'&resource='+resource;

    Http h = new Http();
    HttpRequest req = new HttpRequest();
    req.setBody(reqbody);
    req.setMethod('POST');
    req.setEndpoint('https://login.microsoftonline.com/abc.org/oauth2/token');
    HttpResponse res = h.send(req);

    deserializeResponse resp1 = (deserializeResponse)JSON.deserialize(res.getbody(),deserializeResponse.class);
    String bearerToken = resp1.access_token;     

    JSON2Apex js = new JSON2Apex();
    js.dataAreaId = 'jax';
    js.SegmentCode = subSegmentID;

    String jsonBody = json.serialize(js);    

    Http http1 = new Http();
    HttpRequest req1 = new HttpRequest();


    req1.setEndpoint('https://dev.cloudax.dynamics.com/data/parentAccounts');
    req1.setMethod('POST');
    req1.setTimeout(20000);
    req1.setHeader('Authorization','Bearer '+bearerToken);
    req1.setBody(jsonBody);
    req1.setHeader('Content-Type', 'application/json;charset=UTF-8');
    HttpResponse res1 = http1.send(req1);
   }

I am trying to use the named credentials now. I set the AUTH Provider and Named Credentials and I get the Authenticated status in the Named Credentials like below

enter image description here

So I changed the Apex Callout like

   @future (callout=true)
   public static void createSegmentD365(String subSegmentID) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint('callout:D365Credential/data/parentAccounts');
    req.setHeader('Authorization','Bearer {!$D365Credential.access_token}');
    req.setHeader('Content-Type', 'application/json;charset=UTF-8');
    req.setMethod('POST');
    req.setTimeout(20000);
    req.setBody(jsonBody);
    Http http = new Http();
    HTTPResponse res = http.send(req);
    System.debug('Response Body=========' + res.getBody());      

In the debug I get the Authentication failed, not sure what I am missing here any help is greatly appreciated

enter image description here

Best Answer

This line is not needed when using named credentials as callout endpoints:

req.setHeader('Authorization','Bearer {!$D365Credential.access_token}');

From the example

HttpRequest req = new HttpRequest();
req.setEndpoint('callout:My_Named_Credential/some_path');
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());

Note

I was able to find this question which shows that form assembly has some funky requirements. If you absolutely need to include this header for some reason, I think you're using the wrong merge field. This documentation shows that it should OAuthToken instead of access_token.

req.setHeader('Authorization','Bearer {!$D365Credential.OAuthToken}');
Related Topic