Salesforce OAuth Architecture: Named Credentials, External Credentials, and Auth Providers
Salesforce provides a three-layer authentication architecture for secure API integrations. Understanding how these layers connect is essential for building robust callout-based integrations -- and for avoiding the subtle configuration pitfalls that cause most authentication failures.
The Three Layers
+---------------------+
| Named Credential | <-- Endpoint URL + callout reference
| (Layer 3) | Used directly in Apex code
+----------+----------+
|
v
+---------------------+
| External Credential | <-- Authentication protocol + principal
| (Layer 2) | Links to Auth Provider
+----------+----------+
|
v
+---------------------+
| Auth Provider | <-- OAuth flow definition
| (Layer 1) | Client ID, secret, token URLs
+---------------------+
Layer 1: Auth Provider
The Auth Provider defines the OAuth flow. It specifies the authorization endpoint, token endpoint, client ID, and client secret. Salesforce supports several provider types, including Salesforce-native, OpenID Connect, and custom Auth Providers built with Apex.
For a Salesforce-to-Salesforce integration (or a self-org callout), use the Salesforce provider type and point it to a Connected App in the target org.
Layer 2: External Credential
The External Credential bridges the Auth Provider and the Named Credential. It specifies:
- Authentication Protocol: OAuth 2.0, JWT Bearer, Custom, etc.
- Auth Provider reference: Which Auth Provider handles token acquisition.
- Principal type: Named Principal (shared identity) or Per-User Principal (individual user tokens).
External Credentials also require Permission Set mappings. A Principal must be associated with a Permission Set, and users must be assigned that Permission Set to use the credential.
Layer 3: Named Credential
The Named Credential is the developer-facing abstraction. It defines the endpoint URL and references an External Credential. In Apex, you reference the Named Credential by name -- never hardcoding URLs or tokens.
Self-Org Callout Configuration
A common pattern is calling your own org's REST APIs (e.g., invoking a custom REST endpoint or Composite API from a Queueable job). The configuration flow:
- Connected App: Create in Setup with OAuth enabled. Set the callback URL to include the Auth Provider's callback path:
https://login.salesforce.com/services/authcallback/<AuthProviderUrlSuffix> - Auth Provider: Type = Salesforce. Use the Connected App's consumer key and secret.
- External Credential: Protocol = OAuth 2.0, linked to the Auth Provider, Named Principal.
- Named Credential: URL =
https://yourinstance.my.salesforce.com, linked to the External Credential. - Permission Set: Create one, associate it with the External Credential Principal, assign it to the running user or integration user.
The Callback URL Pitfall
The most common configuration failure occurs when the Connected App's callback URL does not match the Auth Provider's expected callback path. The callback URL must follow this exact format:
https://login.salesforce.com/services/authcallback/<YourAuthProviderURLSuffix>
If you use a custom domain, substitute login.salesforce.com with your My Domain login URL. Mismatches here result in redirect_uri_mismatch errors during the OAuth handshake.
Permission Set Requirement
External Credentials will not function without proper Permission Set configuration. After creating the External Credential:
- Navigate to the External Credential's detail page.
- Under Permission Set Mappings, click New.
- Select the Permission Set and set the Identity Type (Named Principal or Per User).
- Assign the Permission Set to all users who need callout access.
Skipping this step produces 401 Unauthorized errors even when all other configuration is correct.
Apex Callout Example
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:My_Named_Credential/services/data/v60.0/sobjects/Account');
req.setMethod('GET');
Http http = new Http();
HttpResponse res = http.send(req);
if (res.getStatusCode() == 200) {
Map<String, Object> result = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
System.debug(result);
} else {
System.debug('Error: ' + res.getStatusCode() + ' ' + res.getBody());
}
The callout: prefix tells Salesforce to inject the authentication token from the Named Credential automatically.
Troubleshooting Common Errors
| Error | Likely Cause | Resolution |
|---|---|---|
401 Unauthorized | Missing Permission Set mapping on External Credential | Add Permission Set mapping and assign to user |
invalid_grant | Expired or revoked refresh token | Re-authenticate the Named Principal |
redirect_uri_mismatch | Connected App callback URL does not match Auth Provider path | Correct the callback URL in the Connected App |
UNKNOWN_EXCEPTION | External Credential not linked to Auth Provider | Verify the Auth Provider reference on the External Credential |
Key Takeaways
- Always configure bottom-up: Auth Provider first, then External Credential, then Named Credential.
- Permission Sets are mandatory for External Credentials -- this is the most commonly missed step.
- The callback URL must exactly match the Auth Provider's suffix path.
- Use
callout:NamedCredentialNamein Apex to keep credentials out of code entirely.