Skip to content

Salesforce Restricts the OAuth Device Flow on 30 November 2026: Your Connected App Has to Become an External Client App

From 30 November 2026 the OAuth device flow works only from local external client apps. Connected apps that use it must migrate or stop authenticating.

TL;DR

  • From 30 November 2026, the OAuth 2.0 device flow works only from local external client apps with a localhost callback URL.
  • Salesforce's wording leaves no room to wait it out: "For connected apps, you must migrate to external client apps to continue using the device flow."
  • It is not a Winter '27 item. It has its own fixed date, so it lands on every org at once rather than on your upgrade weekend.
  • This is the leading edge of a larger migration. Migrate All Connected Apps to External Client Apps is scheduled for Summer '27, so this work is not extra, it is early.
  • The device flow is used by things without a browser: headless scripts, CI runners, IoT devices, kiosks, anything that asks you to visit a URL and type a code. If nothing in your org does that, this costs you one query to confirm.

What You'll Learn

  • How to confirm in one query whether any app in your org uses the device flow
  • What "local external client app with a localhost callback" actually excludes
  • Why the migration is not optional and where it leads next
  • How this relates to the other OAuth retirements already in flight

The Problem

The device flow exists for clients that cannot host a browser redirect. A CI runner, a script on a server, a device with no keyboard. It works by having the client show a code, the human authenticate elsewhere, and the client poll until the authorisation lands. That indirection is exactly what makes it useful, and exactly what makes it attractive to an attacker: a code displayed on one screen and typed on another is a code that can be displayed on a screen the victim does not control.

Salesforce's response is to constrain where the flow can originate. From 30 November 2026 it is restricted to local external client apps with a localhost callback URL. That combination is deliberate. It permits the legitimate case, a tool running on the machine of the person authenticating, and removes the case where a remote server initiates a flow that a human somewhere else completes.

The part that turns this from a configuration change into a project is the app type. Connected apps cannot satisfy the new criteria at all. Salesforce is explicit: to keep using the device flow, a connected app has to become an external client app.

Quick Answer

From 30 November 2026, Salesforce restricts the OAuth 2.0 device flow to local external client apps with a localhost callback URL. Connected apps using the device flow must be migrated to external client apps or they stop authenticating. The date is fixed rather than tied to your org's release upgrade, so it applies everywhere on the same day. Confirm your exposure in Setup under Connected Apps OAuth Usage, and cross-check Login History for the app names you find, since an app that has not run recently still breaks when it next runs. If you find nothing using the device flow, you are done. If you find something, the migration to an external client app is work you were going to do anyway, because Migrate All Connected Apps to External Client Apps is scheduled for Summer '27 and covers everything else.

Step 1: Find out whether this applies to you

Most orgs will find nothing. Confirming that takes a minute and is worth doing properly rather than assuming.

Start in Setup, under Connected Apps OAuth Usage. That page lists every connected app that has been used to authenticate, which is a smaller and more useful list than every app that exists. For each one that matters, open it and look at the OAuth settings for the enabled flows.

Then check what has actually been authenticating:

SELECT UserId, Application, Status, COUNT(Id) logins
FROM LoginHistory
WHERE LoginTime = LAST_N_DAYS:180
GROUP BY UserId, Application, Status
ORDER BY COUNT(Id) DESC

A note that will save you a parse error: on LoginHistory, Application, Status and ApiType are groupable but not filterable, so you cannot put Application in the WHERE clause. Group first and read the result. The filterable fields are LoginTime, UserId, LoginType, SourceIp and LoginUrl.

Use 180 days rather than 90 here. Device flow clients are frequently the least routine things in an org: a quarterly reconciliation runner, a device that gets switched on for stocktake. A short window is exactly how you miss them.

Step 2: Understand what the new criteria exclude

Two words are doing the work: local and localhost.

A callback of http://localhost:1717/OauthRedirect qualifies. A callback pointing at a server you host, a container, or a public URL does not, no matter how well secured. If the client is not running on the same machine as the person authenticating, the flow is no longer available to it after 30 November.

This is worth reading carefully before planning a migration, because it changes the answer for some architectures rather than just the app type. A headless job on a build server that used the device flow to obtain a token cannot simply be converted into an external client app and carry on. It has no local human and no localhost. That integration needs a different flow entirely, and the sensible destinations are the client credentials flow for server to server work, or the JWT bearer flow where a certificate is preferable to a stored secret. Both are covered in the same terms in the username-password flow retirement guide, which is the other place this decision comes up.

Step 3: Migrate, knowing where it leads

If you do have a genuine local device flow client, the migration is from connected app to external client app.

External client apps are the newer packaging for the same idea, with app configuration separated from policy so the two can be versioned and deployed independently. That separation is the actual reason Salesforce is moving everyone across, and it is why this is not a one-off favour to the device flow.

The scheduling makes the direction obvious. This update enforces on 30 November 2026 for device flow apps specifically. Migrate All Connected Apps to External Client Apps is scheduled for Summer '27 and covers the rest. Doing the device flow apps now is not extra work, it is the first tranche of a migration with a later deadline attached to everything else. Teams that treat it that way get to learn the migration on one or two apps rather than on all of them at once.

Where this sits among the other OAuth changes

Salesforce is retiring or restricting several OAuth flows at once, and the dates are not the same:

Change Enforced
Device flow restricted to local external client apps 30 November 2026
Username-password (ROPC) flow retirement 20 February 2027
User-agent and hybrid user-agent flow retirement 20 February 2027
Migrate all connected apps to external client apps Summer '27

The common direction is away from flows that pass credentials around and towards flows that use a redirect with PKCE, or that authenticate a service rather than a user. If you are opening integration configuration for one of these, it is usually cheaper to survey all of them in the same pass than to come back in February.

Frequently Asked Questions

Q: Does this affect the Salesforce CLI?

A: Not in the versions this post was written against. sf org login offers web, jwt, sfdx-url and access-token, with no device flow subcommand, so CLI authentication is not in scope here. Check your own CLI version rather than taking that as permanent, since the command set changes between releases.

Q: We have a connected app with the device flow enabled but nothing uses it. Do we have to migrate?

A: No, and this is the better outcome. An enabled flow that nothing uses is a permission you can remove rather than migrate. Turn the device flow off in the connected app's OAuth settings, confirm nothing breaks over a full business cycle, and you have reduced the app's surface instead of moving it. That is a better result than a migration, and it takes a fraction of the time.

Q: Is this a Winter '27 release update?

A: No. It sits under Scheduled To Be Enforced Before Spring '27, with its own fixed date of 30 November 2026. That distinction matters for planning: release updates tied to a release arrive on your org's upgrade weekend, which varies by instance, while this arrives everywhere on the same day regardless of which release your org is running.

Q: What actually happens on the date if we do nothing?

A: Affected clients stop being able to complete the device flow. The failure is at authorisation rather than mid-transaction, so there is nothing partial to unpick, and as with the other OAuth changes there is no signal in the Salesforce UI. Whoever operates the device or the script finds out first.

Q: Should we wait, given how often these dates move?

A: The instanced URL update has now slipped three times, so the scepticism is earned. It is misplaced here for a practical reason: the work does not expire. Migrating a connected app to an external client app is required by Summer '27 regardless of what happens to this date, so effort spent now is not wasted if the deadline moves. That is the opposite of the usual wait-and-see calculation.

Key Takeaways

  • 30 November 2026 is a fixed date, not an upgrade-weekend date. It lands on every org simultaneously.
  • Connected apps cannot meet the new criteria. Migration to an external client app is the only path that keeps the device flow.
  • Local and localhost are both requirements. A headless client on a remote server needs a different flow, not a different app type.
  • Most orgs are not affected, and confirming that costs one query against Connected Apps OAuth Usage and Login History.
  • This is the first tranche of a bigger migration, with everything else due in Summer '27, so early work here is not wasted even if the date moves.

What's Next?

Run the Connected Apps OAuth Usage check today. If it comes back clean, note the date and move on. If it does not, decide per app whether you are migrating it or switching it off, because switching off an unused flow is the cheaper answer and it comes up more often than people expect.

Then read the wider release picture in Salesforce Winter '27 Security Readiness, and if you have integrations authenticating with a username and password, that retirement shares both a date and a destination with the user-agent flow changes.

Resources & References

  • Salesforce Release Updates, under Scheduled To Be Enforced Before Spring '27, in Salesforce Help. Confirm the status for your own org in Setup, then Release Updates.
  • Connected Apps OAuth Usage in Setup, for which apps have actually authenticated.
  • LoginHistory object reference, for the filterable and groupable flags that shape the query above.
  • Salesforce Winter '27 Security Readiness for the release as a whole.
  • The username-password flow retirement for the client credentials and JWT bearer alternatives in detail.

Responses

Checking your session.

Loading responses.