[SalesForce] Salesforce REST API Named Credential INVALID_SESSION_ID

I am attempting to call the Salesforce REST API from a Lightning Component. As per their documentation I have set up a named credential using the following settings:

Label: Salesforce REST
Name: SFDC_REST
URL: https://na39.salesforce.com
Certificate: null
Identity Type: Named Principal
Authentication Protocol: Password Authentication
Username: <my_username>
Password: <my_password>
Generate Authorization Header: true
Allow Merge Fields in HTTP Header: false
Allow Merge Fields in HTTP Body: false

All callouts made using this named credential return a 401 response with INVALID_SESSION_ID. I have seen other posts about using a custom merge header for OAuth but I am attempting to use basic auth here. I don't think I can generate my own basic auth header because I can't base64 encode the username/password.

Any insight on why the named credential is failing to authenticate? It seems like this should just be point-and-click setup and that I should just be able to reference the named credential in my endpoint as callout:SFDC_REST/services....

Best Answer

Salesforce doesn't support direct Password Authentication to use the REST API. Typically you would go through an OAuth flow to get a valid access token to then call the service. You could go down this path by creating a Connected App and Authorization Provider, but that seems like a lot of work to get something you already have in Apex.

Instead, in Apex you can just use the UserInfo.getSessionId() in place of the access token in the Authorization header.

I've put together the following anonymous Apex to show how little is required. You will also need to add the Remote Site setting for your URL.

String restApi = URL.getSalesforceBaseUrl().toExternalForm() + '/services/data/v40.0/sobjects/';  

HttpRequest httpRequest = new HttpRequest();
httpRequest.setMethod('GET');
httpRequest.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
httpRequest.setEndpoint(restApi);

try {  
         Http http = new Http();   
         HttpResponse httpResponse = http.send(httpRequest);  
         if (httpResponse.getStatusCode() == 200 ) {
             string response = JSON.serializePretty( JSON.deserializeUntyped(httpResponse.getBody()) );  
             System.debug('REST API Response : ' + response );
         } else {  
               System.debug('httpResponse: ' + httpResponse.getBody());
               throw new CalloutException(httpResponse.getBody());
         }   

} catch( System.Exception e) {
         System.debug(LoggingLevel.ERROR, 'ERROR: '+ e);
         throw e;
}