Named Credentials and External Credentials are Salesforce’s recommended way to connect to outside systems without hardcoding endpoints, tokens, or passwords in Apex. Once authentication details live in an external credential, they’re encrypted at rest, hidden from view in setup, and never printed in debug logs—but we can still reference them safely from a named credential’s URL, headers, or body using merge-field syntax.
This guide walks through the full setup—creating an External Credential, a Principal, and a Named Credential, and then shows exactly how to reference External Credential parameters using {!$Credential...} syntax, with a working Apex example that generates a Salesforce OAuth access token.
Quick Answer
We cannot read an External Credential parameter’s raw value directly in Apex (String secret = ...it is not possible by design). Instead, we reference it as a merge field inside the Named Credential’s URL, HTTP header formula, or HTTP body formula using:
{!$Credential.<ExternalCredentialName>.<ParameterName>}
Salesforce resolves this merge field server-side, at callout time, and injects the value into the outgoing HTTP request. Apex only ever calls Http.send() against the Named Credential (callout:MyNamedCredential/...) — it never touches the secret itself.
What Are Named Credentials and External Credentials?
A Named Credential defines the target endpoint our Apex callout points to the base URL, whether callouts are allowed, and how the authorization header should be generated. It’s the object we actually reference in code with callout:NamedCredentialName.
An External Credential defines how to authenticate to that endpoint — the auth protocol (Basic Auth, custom, OAuth, AWS Signature, etc.), the parameters it needs (client ID, secret, username, password, tokens), and who is allowed to use it (via Principals and Permission Sets).
Since the Winter ’21 release, Salesforce split what used to be one object (the legacy Named Credential) into these two objects, separating where we’re connecting from and how we authenticate. This split is what lets one External Credential be reused across multiple Named Credentials, and lets us scope authentication per-user or per-org independently of the endpoint.
Named Credential vs External Credential
| Attribute | Named Credential | External Credential |
|---|---|---|
| Purpose | Points to the external endpoint (URL) | Stores authentication configuration |
| Contains | Base URL, callout options, header generation settings | Auth protocol, parameters (secrets), principals |
| Referenced in Apex as | callout:MyNamedCredential/path | Never called directly—used behind the Named Credential |
| Reusable across multiple records | No — one URL per Named Credential | Yes—one External Credential can back several Named Credentials |
| Where secrets live | Never | Here, inside Principals |
External Credential Architecture
An External Credential is made up of three pieces that fit together:
- Authentication Protocol — the type of auth flow: Custom, Per-User Basic/Header, OAuth 2.0 (Browser Flow, JWT Bearer, Client Credentials), or AWS Signature Version 4.
- Principals — the identity used to authenticate. A Named Principal is a single shared identity used by everyone accessing that Named Credential (org-wide). A Per-User Principal lets each individual Salesforce user authenticate with their own credentials.
- Parameters — key/value pairs attached to a Principal (Authentication Parameters) or to the External Credential itself (Custom Headers). This is where
client_id,client_secret,username,password, tokens, and similar values live.
Permission Sets grant access to a Principal via External Credential Principal Access, which is how we control who in our org can use a given identity to make callouts.
How External Credential Parameters Work
When we add an Authentication Parameter to a Principal, Salesforce stores the value encrypted and marks it non-retrievable through normal means—it won’t show up in the UI after saving, in Setup Audit Trail, in Data Loader exports, or in an Apex debug log. The only sanctioned way to use that value is to reference it as a merge field inside a Named Credential’s:
- URL
- Generate Authorization Header formula
- Custom HTTP Header value (if “Allow Formulas in HTTP Header” is enabled)
- HTTP Body (if “Allow Formulas in HTTP Body” is enabled, useful for
x-www-form-urlencodedbodies like OAuth token requests)
At callout time, the Salesforce platform resolves the merge field, substitutes the real value into the request, and sends it over the wire—all outside of Apex’s visibility. This is the core security guarantee: the secret exists only in Salesforce’s credential store and in the outbound HTTP request, never in our code, logs, or heap.
Use Case Scenario
Our Salesforce application needs to authenticate with a partner Salesforce org using OAuth 2.0. The partner provides a client ID, client secret, integration username, password, and security token. Instead of hard-coding these credentials in Apex, we store them securely in an External Credential and use a Named Credential to construct the OAuth token request at runtime.
Let us handle this scenario step by step.
Create an External Credential
For this use case, we need to connect to the partner Salesforce API. The partner will create an external client app to allow us to integrate with their org. Once the external client app is created, they will share the below details.
| client_id | Client ID / Consumer Key from the partner’s External Client App |
| client_secret | Client Secret / Consumer Secret from the partner’s External Client App. |
| username | Salesforce username that will be used to authenticate |
| password | Salesforce username password + security token for the user. |
Go to Setup → Named Credentials → External Credentials → New, and create one named Salesforce Login EC using the Custom authentication protocol. A custom protocol gives us full control over which parameters we define and how they’re referenced—it’s the right choice whenever we’re not using Salesforce’s built-in OAuth flows.

Create a Principal
Under the External Credential, add a Named Principal — for example, SFLoginPrincipal — since this token generation will use a single shared Salesforce integration user rather than per-user credentials.
Add these Authentication Parameters to the principal:
| Parameter | Value |
|---|---|
client_id | Client ID / Consumer Key from the partner’s External Client App |
client_secret | Client Secret / Consumer Secret from the partner’s External Client App |
username | Salesforce username used to authenticate |
password | Salesforce password + security token, concatenated |
grant_type | password (hardcoded literal, not sensitive) |
Once saved, these values are encrypted and no longer visible in the UI — only their parameter names remain.

Grant Principal Access
Create a Permission Set — for example, Salesforce Login PS — and under External Credential Principal Access, add the Salesforce Login EC → SFLoginPrincipal principal. Assign this Permission Set to any user who needs the running Apex context to be able to use this credential.
This step is easy to miss: without it, callouts fail with an authentication or access error even though the External Credential and Named Credential are configured correctly. Principal access is enforced independently of object and field-level security.
Create a Named Credential
Go to Setup → Named Credentials → New, and create Salesforce Login NC with:
| Setting | Value |
|---|---|
| URL | https://login.salesforce.com/services/oauth2/token |
| Allow Callout | Checked |
| External Credential | Salesforce Login EC |
| Generate Authorization Header | Checked |
| Allow Formulas in HTTP Header | Checked |
| Allow Formulas in HTTP Body | Checked |

Allow Formulas in HTTP Body is what lets us build the x-www-form-urlencoded OAuth request body using merge fields—without it, we can’t inject client_id, client_secret,username, password, orgrant_type into the POST body at all.
Reference External Credential Parameters with $Credential
Inside the Named Credential’s URL, header, or body formula fields, reference a parameter with:
{!$Credential.<External Credential Name>.<Parameter Name>}
For example, to reference the client_id parameter defined on the Salesforce Login EC External Credential:
{!$Credential.SalesforceLoginEC.client_id}
Note that the External Credential name in the merge field is the API name (no spaces), not the label—so “Salesforce Login EC” becomes SalesforceLoginEC in the formula.
Example: API Key Authentication
The same pattern applies to simpler auth schemes. If we’re calling a third-party REST API that expects a static API key in a custom header, define a single api_key parameter on the Principal, then set a custom header on the Named Credential:
| Header Name | Header Value |
|---|---|
x-api-key | {!$Credential.ThirdPartyEC.api_key} |
No Apex code ever sees the raw key — Salesforce substitutes it into the header when the callout fires.
Example: Using Named Credential from Apex
With the Named Credential and External Credential in place, build the HTTP body using merge fields and let Salesforce resolve them at send time:
Test it from the Developer Console’s Execute anonymous window:
System.debug(JSON.serializePretty(
AccessTokenGenerator.generateToken('SalesforceLoginNC')
));
The response returns the standard OAuth token payload—access_token, instance_url, id, token_type, issued_at, and signature—with the actual client credentials never appearing in our Apex heap, debug logs, or exception stack traces.

Can Apex Directly Read a Secret?
No — and this is intentional, not a limitation to work around. There is no Apex method, no Named/External Credential SOQL field, and no Metadata API call that returns a parameter’s plaintext value once it’s saved. Salesforce enforces this at the platform level so that a compromised Apex class, a rogue debug log, or an over-permissioned integration user can’t be used to exfiltrate credentials.
Troubleshooting Common Parameter Problems
- Unauthorized endpoint or callout fails silently with no data in the body: Check “Allow Formulas in HTTP Body” on the Named Credential. Without it, merge fields in the body are sent as literal text instead of being resolved.
- Merge field renders as literal text instead of the value: Double-check the External Credential API name matches exactly (case-sensitive, no spaces) and that the parameter name matches what was defined on the Principal, not a guessed name.
- Insufficient Access or authentication failure despite correct parameters: The running user is missing External Credential Principal Access. Verify their Permission Set includes the specific Principal (not just the External Credential).
- Parameter changes don’t seem to take effect: Named/External Credential metadata can be cached briefly at the platform level after a Setup change; a few minutes’ wait or a fresh session usually resolves it.
- Works in Execute Anonymous but fails from a trigger or async context: Confirm the running user context (trigger user, queueable/batch context) also has the permission set assigned. Anonymous Apex runs as the logged-in admin, which can mask missing permissions in production contexts.
External Credential Parameter vs Custom Metadata
Custom metadata can also store API key information. Sometimes it’s tempting to store API keys in a custom metadata type, as it’s easy to query from Apex. The difference of these two matters:
| External Credential Parameter | Custom Metadata Type | |
|---|---|---|
| Encrypted at rest | Yes | No (readable as plain text) |
| Visible via SOQL from Apex | No | Yes |
| Visible in Setup Audit Trail / exports | No | Yes |
| Appropriate for secrets (passwords, tokens, keys) | Yes | No |
| Appropriate for non-sensitive config (endpoint toggles, feature flags) | No | Yes |
Use Custom Metadata for configuration values that aren’t sensitive — timeout settings, feature toggles, non-secret business rules. Use External Credential parameters for anything that authenticates us to another system.
Security Best Practices
- Prefer Named Principals for shared integration users, Per-User Principals when each Salesforce user must authenticate individually (e.g., logging in as themselves to a partner system).
- Scope Permission Set assignment tightly. Only assign External Credential Principal Access to users and integration contexts that genuinely need it—treat it like any other sensitive permission.
- Rotate credentials periodically, especially Consumer Secrets and passwords, and update the Principal’s parameters rather than embedding new values elsewhere.
- Avoid logging response bodies that might echo back request parameters. Some APIs echo request data in error responses—review before debugging in logs that persist.
- Use named, not wildcard, custom headers so we can audit exactly what’s being sent per integration.
- Favor OAuth Client Credentials or JWT Bearer flows over the username-password flow where the target system supports it—the example above uses the password grant for illustration, but token-based or certificate-based flows avoid storing a raw password entirely.
Legacy vs Modern Named Credentials
Salesforce still supports “legacy” Named Credentials, which combine the endpoint and authentication into a single record — no separate External Credential object. They still work, but Salesforce has been steering new development toward the split model (Named Credential + External Credential) since its introduction, since it enables per-user authentication, reusable auth configs across multiple endpoints, and finer-grained permission control.
If we’re building new integrations, use the External Credential model described in this guide. If we are maintaining an org with legacy Named Credentials, Salesforce provides a migration path in Setup to convert them without rebuilding callout code, since Apex still just references callout:CredentialName either way.
External Client Apps and OAuth
External Client Apps are the next generation of Connected Apps, designed to provide improved security, clearer separation between developer and administrator responsibilities, and better packaging and distribution capabilities. Salesforce recommends using External Client Apps for new integrations. Existing Connected Apps continue to work, but creation of new Connected Apps is restricted as of Spring ’26.
When our External Credential uses the OAuth 2.0 protocols (Browser Flow, JWT Bearer, Client Credentials) rather than Custom, the Consumer Key and Consumer Secret come from this External Client App/Connected App record, and Salesforce handles the token refresh lifecycle automatically — we don’t need to manually re-request tokens the way the Custom-protocol example above does. For high-volume integrations, an OAuth-protocol External Credential is generally preferable to the manual password-grant approach for exactly this reason: token caching and refresh are handled by the platform.
FAQ
1. Can I see the value of an External Credential parameter after I save it?
No. Once saved, the UI shows only the parameter name, never the value — by design.
2. Can I use the same External Credential for multiple Named Credentials?
Yes. That’s one of the main advantages of the split model — define authentication once, reuse it across several endpoints that share the same identity.
3. Do External Credential parameters count against any Apex governor limits?
No. Merge field resolution happens outside Apex execution, so it doesn’t consume heap size, CPU time, or callout limits beyond the callout itself.
4. Can Flow or Lightning Web Components use External Credential parameters the same way?\
Flow’s HTTP Callout action and LWC (via Apex or fetch against a Named Credential in supported contexts) both go through the same Named Credential, so the same merge-field mechanism applies—the parameters are still resolved by the platform, not by our Flow or LWC logic.
5. What happens if I reference a parameter name that doesn’t exist? The merge field typically resolves to an empty string rather than throwing an error, which is why the “renders as literal text” troubleshooting step above is worth checking first — a typo silently produces a blank value instead of a callout error.
Conclusion
External Credentials exist specifically so that Apex developers never need direct access to plaintext secrets. By defining parameters on a Principal and referencing them with {!$Credential.<ExternalCredentialName>.<ParameterName>} inside a Named Credential’s URL, header, or body, we keep authentication data encrypted, auditable through Permission Set access rather than code review, and completely absent from debug logs — while our Apex code stays as simple as a callout to callout:NamedCredentialName.
Related Salesforce Integration Guides
- Generate Salesforce Authentication Token using Postman
- Create Jira Issue in Salesforce Apex with Jira Integration
- Seamless YouTube Video API Integration in Salesforce
- GraphQL Query Generator in Salesforce Apex
- Top Salesforce Integration Architect Interview Questions and Answers
- Salesforce integration patterns
- Ultimate Guide to Integrate Stripe with Salesforce CRM
References:
Updated for 2026
Salesforce’s current Named Credential architecture uses extensible/customizable Named Credentials together with External Credentials. Legacy Named Credentials are deprecated and Salesforce recommends the newer model
References:
Need Help?
Need some kind of help in implementing this feature, connect on my LinkedIn profile Dhanik Lal Sahni.

Dhanik Lal Sahni is a Salesforce Solution Architect, Independent Consultant, and the founder of SalesforceCodex.com. With nearly two decades of IT experience and extensive expertise in Salesforce architecture, he helps startups and enterprises design scalable, secure, and high-performance CRM solutions using Sales Cloud, Service Cloud, Experience Cloud, Data Cloud, Apex, Lightning Web Components (LWC), and enterprise integration patterns.
Through SalesforceCodex, he shares practical tutorials, real-world implementation guides, enterprise architecture best practices, and interview preparation resources for Salesforce Developers, Architects, and Administrators.
Learn more about his Salesforce consulting and freelance services at dhaniksahni.com.
