Almost every Salesforce Org will make use of a third party web service for something. It could be something as simple as posting to Twitter, to a complex integration with a third party orders and payments system.
The new Named Credentials feature streamlines and simplify the process of using authenticating with third party web services within Apex code.
The most common forms of authentication are HTTP Basic authentication and OAuth. Both methods of authentication are relatively simple to do in code, with OAuth being the slightly more complicated of the two.
However, questions start to arise when it comes to the user credentials for these services.
- Where do you store them?
- How do you protect them?
- How do you handle different users having different credentials?
Named Credentials solve all of these problems for the vast majority of web services and are incredibly easy to set up.
Named Credentials can be used with for both HTTP Basic authentication (Password Authentication) and OAuth 2.0 authentication and can be set up on a per user or organization-wide (Named Principal) basis.
You can also use Named Credentials for anonymous web services, but there are minimal advantages to using them in those cases.
HTTP Basic authentication
Lets take a look at a basic example using HTTP Basic authentication for an
HttpRequest in Apex:
This isn’t too complicated but as you can see the username and password are hard-coded and we have to build the Authentication header manually.
HttpRequest req = new HttpRequest(); req.setEndpoint('https://api.example.com/path'); req.setMethod('GET'); String username = 'username'; String password = 'password'; Blob headerValue = Blob.valueOf(username + ':' + password); String authorizationHeader = 'BASIC ' + EncodingUtil.base64Encode(headerValue); req.setHeader('Authorization', authorizationHeader); Http http = new Http(); HttpResponse res = http.send(req); System.debug(res.getBody());
You also need to make sure that the endpoint you are calling has been defined in Remote Site Settings for this to work.
You could store the username and password in a custom object or custom setting, but then you have to worry about retrieving those details in your code which adds additional complexity.
How does it look with Named Credentials?
First define a Named Credential with the following values:
|Label||HTTP Basic Credential|
|Identity Type||Named Principal|
|Authentication Protocol||Password Authentication|
Once you’ve done this your code for the callout becomes the following:
As you can see, this is much simpler and cleaner. The hard-coded username and password are gone and as an added bonus, any endpoint that is defined as a Named Credential doesn’t need to be added to Remote Site Settings, so that’s one little piece of admin you don’t have to worry about.
HttpRequest req = new HttpRequest(); req.setEndpoint('callout:HTTP_Basic_Credential/path'); req.setMethod('GET'); Http http = new Http(); HttpResponse res = http.send(req); System.debug(res.getBody());
Here is an example of retrieving a user’s Chatter feed from another Salesforce Org using the Username-Password OAuth Authentication Flow.
Doing it this way there is quite a lot of code involved, and you need to make two HTTP requests.
HttpRequest loginRequest = new HttpRequest(); loginRequest.setEndpoint('https://login.salesforce.com/services/oauth2/token'); loginRequest.setMethod('POST'); loginRequest.setHeader('Content-Type', 'application/x-www-form-urlencoded'); String clientId = 'client_id'; String clientSecret = 'client_secret'; String username = 'username'; String password = 'password'; String securityToken = 'security_token'; String body = 'grant_type=password&client_id=' + clientId + '&client_secret=' + clientSecret + '&username=' + username + '&password=' + password + securityToken; loginRequest.setBody(body); Http http = new Http(); HttpResponse loginResponse = http.send(loginRequest); Map<String, String> loginResponseBody = (Map<String, String>)JSON.deserialize(loginResponse.getBody(), Map<String, String>.class); HttpRequest feedRequest = new HttpRequest(); feedRequest.setEndpoint(loginResponseBody.get('instance_url') + '/services/data/v32.0/chatter/feeds/news/me/feed-elements'); feedRequest.setMethod('GET'); String authorizationHeader = 'Bearer ' + loginResponseBody.get('access_token'); feedRequest.setHeader('Authorization', authorizationHeader); HttpResponse feedResponse = http.send(feedRequest); System.debug(feedResponse.getBody());
As an alternative you could use an access token stored from a previous request or use one of the other flows and store the access token rather than using the username-password flow each time, but those solutions are still more complicated than using Named Credentials.
Using Named Credentials for OAuth 2.0
Using Named Credentials with OAuth is a little more complicated then with HTTP Basic authentication.
You’ll need to create an Authentication Provider (and in this example you also need a Connected App so that you can request the
chatter_api scope in your Authentication Provider). I won’t go into detail on creating those in this post but the linked documentation should point you in the right direction.
Once you’ve got that all set up you can define your Named Credential with the following details:
|Identity Type||Named Principal|
|Authentication Protocol||OAuth 2.0|
|Authentication Provider||Your Authentication Provider|
Then when you hit the Save button you can authenticate against your other Salesforce Org and the access token will be saved automatically behind the scenes.
You can even add the
refresh_token scope to your Connected App and Named Credential and then you don’t have to worry about re-authenticating each time your access token expires.
Once that’s done the Apex code to make the web service callout is vastly reduced and ends up being just the following.
That’s much simpler! Right?
HttpRequest feedRequest = new HttpRequest(); feedRequest.setEndpoint('callout:OAuth_Credential/services/data/v32.0/chatter/feeds/news/me/feed-elements'); feedRequest.setMethod('GET'); Http http = new Http(); HttpResponse feedResponse = http.send(feedRequest); System.debug(feedResponse.getBody());
Per User Credentials
I’ve only touched on examples using the Named Principle (Organization-Wide) Identity Type in this post.
You can also use the Per User Identity Type to allow each individual user to have their own set of login details for your external service if required (for example for a Facebook or Twitter integration).
You can then provide users access to Named Credentials using their profile or a permission set, once they have access they can set up their personal Named Credentials within their My Settings page.
Now go and use it!
As you can see, Named Credentials is an incredibly useful new feature, especially when it comes to OAuth based web services and situations where you need to have different logins per user.
There are also advantages for simple situations as well, such as moving usernames and passwords out of code and/or removing the need for complex custom object/setting driven solutions and instead putting control and security of your login details for third party services in Salesforce’s capable hands.
In addition to all of this, since Named Credentials are referred to by name, you can have different endpoint URLs in production and your test environments. All you have to do is make sure the Named Credential you are using has the same name in both and everything will “just work”.
Finally, as an added bonus using Named Credentials reduces the amount of code you have to write!