---
title: "External Credentials and the new auth model"
url: "https://trailassembly.com/external-credentials/"
topic: "Admin and Permissions"
published: "2026-09-21T11:45:40+00:00"
updated: "2026-09-23T10:55:10+00:00"
---

# External Credentials and the new auth model

**A Named Credential now holds the URL and points at an External Credential, which holds the authentication.** That split is the whole change. The authentication config is reusable across endpoints, access to it is granted through permission sets rather than being implicit, and per-user OAuth is a first-class option instead of a special case.

## The new shape

| Object | Holds |
| --- | --- |
| Named Credential | The endpoint URL, callout options, and a link to an External Credential |
| External Credential | The authentication protocol and its parameters |
| Principal | A named identity under the External Credential — per-org, per-user, or per-named-principal |
| Permission set | Grants a user access to a principal |

Apex does not change. You still write `callout:My_Named_Credential/path` and the platform resolves and injects the credential. What changed is everything behind that string.

```apex
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:Billing_API/v2/invoices');
req.setMethod('GET');
req.setTimeout(30000);
HttpResponse res = new Http().send(req);
```

## The part that catches everyone: the permission set

Under the legacy model, a named credential worked for anybody whose code called it. Under the new model, the running user must have access to the External Credential Principal, granted through a permission set’s External Credential Principal Access.

Miss that step and the callout fails with an error about the endpoint not being found or not being authorised — which sends people to check the URL and the remote site settings, neither of which is the problem. If a new-style callout fails for one user and works for you, check the permission set before anything else.

Setup → Permission Sets → your set → External Credential Principal Access → add the principal.

## Authentication protocols, and which to pick

**OAuth 2.0.** The default choice for a modern API. Choose the flow to match the relationship: client credentials for a service-to-service integration where Salesforce acts as itself. Authorisation code where each user authenticates as themselves. JWT bearer where you hold a signing certificate and want no interactive step.

**Custom.** For APIs that authenticate with a static key in a header. You define named parameters on the External Credential and reference them in the Named Credential’s headers. Nothing is hardcoded in Apex, which is the point.

```apex
// Header value on the Named Credential
{!$Credential.BillingAPI.ApiKey}
```

**AWS Signature V4.** Built in, which saves implementing request signing by hand. This alone is worth the migration for anyone calling AWS services from Apex.

**Basic.** Available, and a last resort. If the API offers anything else, use it.

## Per-user authentication, done properly

Set the principal type to Per User and each user authenticates individually. The platform stores their token against their identity. The remote system then sees the actual person, which is what audit and per-user permissions on the far side require.

The operational cost is real and should be planned for, not discovered:

- Every user completes an authentication step before their first callout.

- Tokens expire, and a user whose token has lapsed gets a failure at the moment they try to use the feature.

- Batch and scheduled Apex has no interactive user, so per-user principals do not work there. Background work needs a named principal.

My rule: per-user where the remote system enforces per-user permissions or writes an audit trail that has to name a person. Named principal everywhere else, because it is dramatically less to operate.

## Migrating from legacy named credentials

Legacy named credentials continue to work, so this is not a fire drill. Do it when you touch the integration anyway.

1. Create the External Credential with the protocol and principal.

2. Grant principal access in a permission set and assign it — including to the integration user, which is the step most often missed.

3. Create a new Named Credential pointing at it, with a new name.

4. Change the Apex endpoint string to the new name, in one integration at a time.

5. Delete the legacy credential only after a full cycle has run. Including the monthly job nobody thought about.

Keeping both alive during the transition is what makes this safe. Renaming in place to avoid an Apex change is the version of this that causes an incident.

## What does not change

Callout limits are unchanged: 100 per transaction, 120 seconds cumulative, 10 seconds default per call. A named credential does not exempt you from [the DML-before-callout rule](https://trailassembly.com/uncommitted-work-pending/). And the remote system still has to be reachable. Credentials are not connectivity.

## Frequently asked

### Do I have to migrate?

Legacy named credentials still function. New capabilities (AWS signing, per-user principals, reusable auth across endpoints) are only in the new model, so migrate when you need one of them or when you are editing the integration for other reasons.

### Can two named credentials share one external credential?

Yes, and that is the main structural benefit. One authentication definition, many endpoints on the same system.

### Why does my callout work as an admin but not as a user?

Almost certainly missing External Credential Principal Access on that user’s permission set. This is the single most common new-model failure.

### Does this work in scratch orgs and sandboxes?

Yes, though secrets do not travel with metadata. Expect to re-enter credentials after every sandbox refresh and in each new scratch org, and script the rest so only the secret is manual.

### Can I read the secret back out?

No. Credential values are write-only from Setup and are not retrievable through the API or metadata. That is the intended behaviour and it means your source of truth for secrets has to be a secret manager, not Salesforce.

---

*Reference: [Named Credentials as Callout Endpoints](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_callouts_named_credentials.htm), Salesforce Apex Developer Guide; External Credentials* and *Named Credentials*, Salesforce Help.

---

Source: https://trailassembly.com/external-credentials/
Trail Assembly — independent Salesforce write-ups.
