TL;DR
- Legacy Named Credentials are deprecated. Salesforce has said they will be discontinued in a future release but has not published a retirement date, so treat this as overdue technical debt rather than a countdown.
- It is not on Salesforce's list of items scheduled for enforcement in Winter '27. It earns a place on the same to-do list because it touches exactly the same integrations you are already opening for the OAuth and instanced URL changes.
- The legacy format's problem is structural: one record holds the endpoint, the authentication, and the secret, and there is no way to control which users or which Apex can use it beyond who can see the record.
- The modern split separates the two. An External Credential holds the authentication and its principals, a Named Credential holds the endpoint, and access is granted through permission sets like any other capability.
- Setup flags legacy records with a warning and offers a Migrate button. The migration itself is usually minutes. The work is the testing and the permission set design around it.
What You'll Learn
- What changed when Salesforce split Named Credentials in Winter '23, and why
- The specific security weaknesses in the legacy single-record format
- How to inventory which of your credentials are legacy
- How the migration works, and what the Migrate button does and does not do
- How to grant credential access through permission set principals instead of implicitly
The Problem
Named Credentials are the good pattern. They are how you keep an endpoint and its secret out of Apex, out of config files, and out of the repository, and any org that uses them is already ahead of one that hardcodes a bearer token in a helper class.
The trouble is that the original design put too much into one object. A legacy Named Credential is a single record holding the endpoint URL, the authentication protocol, the credential itself, and the identity type. Everything about that integration lives in one place, and the only access control is who can see and reference the record.
That has a specific consequence worth naming: you cannot say "this permission set may use this credential". Any Apex that can make the callout can use it, and separating a low-trust integration from a high-trust one means hoping nobody writes the wrong line of code. For a credential that reaches a payroll system or a partner API, that is a weak boundary.
Salesforce fixed this in Winter '23 by splitting the object in two, and has been steering people to the new format ever since. Legacy records still work today, they receive no further enhancement, and they are on a stated path to removal.
Common questions this article answers:
- Is there a deadline for this, and is it part of Winter '27?
- What is actually wrong with the legacy format beyond it being old?
- How do I find my legacy credentials and migrate them safely?
Quick Answer
Legacy Named Credentials are deprecated with no announced retirement date, so this is not a Winter '27 enforcement and nothing breaks in October because of it. Migrate anyway, because the legacy format combines the endpoint, the authentication, and the secret into one record with no permission-set-level control over who can use it. The modern model splits this: an External Credential holds the authentication protocol and its principals, a Named Credential holds the endpoint and points at the External Credential, and you grant access by adding the External Credential Principal to a permission set. To find your legacy records, open Setup then Named Credentials and look for the warning banner and the older record type, or retrieve NamedCredential and ExternalCredential metadata with the sf CLI and look for Named Credentials with no linked External Credential. Salesforce provides a Migrate button on each legacy record that creates the matching External Credential for you. Budget your effort for testing and permission set design rather than the migration itself, and do it in the same pass as the Winter '27 integration work since it touches the same connections.
What changed in Winter '23
The split maps onto a distinction that was always implicit and is now explicit.
| Concern | Legacy Named Credential | Modern model |
|---|---|---|
| Where the call goes | Named Credential | Named Credential |
| How you authenticate | Named Credential | External Credential |
| The secret itself | Named Credential | External Credential principal |
| Who may use it | Anyone who can call it | Permission sets granted the principal |
| Per-user credentials | Limited | Per-user principals supported properly |
The practical shape is that one External Credential can serve several Named Credentials. If a vendor exposes three API hosts behind one set of credentials, you configure the authentication once and point three Named Credentials at it, which is both less work and fewer copies of a secret.
The part that matters for security is the last two rows. An External Credential has principals, and a principal is something you grant through a permission set. Access to a credential becomes a capability you assign deliberately, visible in the same place as every other capability, rather than a side effect of being able to run Apex. That is the same argument we make about integration permissions generally in Connected app least privilege: granted versus used.
Finding your legacy credentials
In Setup. Open Setup, then Named Credentials. Legacy records are distinguished from the newer format in the list, and opening one shows a warning that it is a legacy record along with a Migrate button. If your org has a handful of credentials, this is the fastest route and you can stop here.
From the metadata, which is better if you have many, or if you want the inventory in version control alongside everything else:
# Retrieve both credential types
sf project retrieve start \
--metadata NamedCredential ExternalCredential \
--target-org myorg
Then look at what came back. A modern Named Credential references an External Credential; a legacy one does not, because in the legacy format there is nothing to reference:
# Named Credentials with no linked External Credential are the legacy ones
grep -L "externalCredential" force-app/main/default/namedCredentials/*.namedCredential-meta.xml
That gives you the list. Note that grep -L prints the files without a match, which is what you want here: the absence of the link is the signal.
For each one, record what calls it before you touch anything. Search your Apex, Flow HTTP callout actions, and any External Services for the credential's name, because a Named Credential is referenced by name and the reference is a string. This is the step people skip and then regret.
Running the migration
The Migrate button on a legacy record creates the External Credential and links the Named Credential to it, carrying across the authentication configuration. For most credentials that is genuinely the whole technical migration.
What it does not do is the part you have to think about:
It does not design your permission sets. After migration, access flows through External Credential Principals granted in permission sets. You have to decide which permission set carries which principal, which is the entire benefit of the change. Dumping every principal into one broad permission set that everybody already holds recreates the legacy problem in new syntax.
It does not re-enter secrets that could not be carried across. Depending on the authentication protocol, you may need to re-enter a client secret or re-authorise an OAuth flow. Have the credentials to hand before you start, particularly for anything a vendor issued once and emailed to somebody who has since left.
It does not test your callouts. The Named Credential keeps its name, so Apex referencing callout:My_Service continues to compile and continues to point at the same thing. That is reassuring, and it is also why a broken migration can look fine until the callout actually runs. Execute a real callout for each credential.
A workable sequence:
- Migrate in a sandbox first, one credential at a time rather than all at once, so a failure has an obvious cause.
- Build the permission set, adding the External Credential Principal to a set that reflects who genuinely needs that integration. Start narrow.
- Run a real callout as a user who holds the permission set, and then as one who does not, to confirm the boundary works in both directions.
- Deploy the permission sets as metadata so the grant is version controlled rather than clicked into production. Deployable permission sets for delivery teams covers that pattern.
- Repeat in production, during business hours, with the integration owner available.
Step three is the one to insist on. Testing that it works is half a test. Testing that it fails for somebody without the permission set is what tells you the boundary is real, and it is the only evidence that the migration bought you anything.
What your users will see
Nothing. This change is entirely server-side and no end user has any visibility into it, so there is no user comms to write.
The people who do need telling are your integration owners and developers, and the message is a standing one rather than an announcement:
We are moving our Salesforce integration credentials to the current format, where the authentication lives in an External Credential and access is granted through a permission set. If you build something that needs to call an external system, do not create a legacy Named Credential, and do not ask for a broad permission set that already has every principal in it. Tell us which system you need to reach and we will grant that one credential to the permission set your work actually uses.
That framing matters more than it looks. The failure mode for this migration is not technical, it is that six months later somebody has created a permission set called "Integration Access" containing every principal in the org, and you are back where you started with extra steps.
Frequently Asked Questions
Q: Is this part of Winter '27? Will something break in October?
A: No. Legacy Named Credentials are deprecated, not retired, and Salesforce has not published a date for their removal. Nothing breaks at Winter '27 because of this. The reason to do it now is that you are already opening every integration's configuration for the OAuth username-password retirement and the instanced URL change, both of which do enforce with Winter '27, and doing three things in one pass is cheaper than three passes.
Q: What actually happens to my Apex when I migrate?
A: Nothing, if you keep the Named Credential's name. Apex references a Named Credential by name in the callout endpoint, for example callout:My_Service/path, and that reference is unchanged by the migration. This is also why you must run a real callout to verify, since compilation success proves nothing here.
Q: Can one External Credential serve several Named Credentials?
A: Yes, and it is the intended pattern when a vendor exposes multiple hosts behind one set of credentials. You configure the authentication once and point several Named Credentials at it, which reduces the number of places the secret exists.
Q: We have dozens of legacy credentials. Is there a bulk migration?
A: The Migrate button works one record at a time, which is tedious at volume but is not the real cost. The real cost is deciding the permission set model and testing each callout, and neither of those is something you would want bulk-applied. Work through them in priority order, starting with the credentials that reach the most sensitive systems.
Q: How do I stop new legacy credentials being created?
A: Make it a review item rather than relying on a setting. Legacy credentials tend to reappear because somebody follows an old internal runbook or a stale blog post, so the durable fix is updating your own documentation and checking for the pattern in code review. Retrieving NamedCredential metadata periodically and re-running the grep -L check above will catch any that slip through.
Key Takeaways
- Legacy Named Credentials are deprecated with no published end date, so this is technical debt with a deadline attached later, not a Winter '27 enforcement.
- The legacy format's weakness is structural: endpoint, authentication, and secret in one record, with no permission-set control over who may use it.
- The modern split makes credential access a capability you grant, through External Credential Principals in permission sets.
- The Migrate button handles the technical move. Your work is the permission set design and testing each callout for real.
- Test the negative case, confirming the callout fails for a user without the permission set. Otherwise you have no evidence the new boundary exists.
What's Next?
Recommended Reading:
- Salesforce Winter '27 Security Readiness: The Five Release Updates and the Sandbox Window to Test Them
- Salesforce Retires the OAuth Username-Password Flow in Winter '27
- Connected app least privilege: granted versus used
- Deployable permission sets for delivery teams
Action Items:
- Retrieve
NamedCredentialandExternalCredentialmetadata and run thegrep -L "externalCredential"check to list every legacy record. - For each one, find its callers in Apex, Flow, and External Services before touching it, then migrate in a sandbox one record at a time.
- Grant each External Credential Principal through a narrow permission set, deploy those sets as metadata, and test that the callout fails for a user without the set.