Companion to the username-password flow retirement, which enforces on the same day and catches a completely different set of integrations.
TL;DR
- Salesforce is retiring the OAuth user-agent flow and the OAuth hybrid user-agent flow, enforced on 20 February 2027.
- These are the flows that return an access token in the URL fragment. That is the whole reason they are being retired: the token arrives somewhere the browser keeps and other code on the page can reach.
- The replacement is the web-server flow or the hybrid web-server flow, both with PKCE.
- The same date carries the username-password retirement, and the two live in different halves of an estate. Username-password is middleware and scripts. User-agent is browsers, single page apps and mobile. Auditing one tells you nothing about the other.
- The affected clients are usually the ones nobody calls an integration: an internal dashboard, a Canvas app, a mobile app built years ago by someone who has left.
What You'll Learn
- Why a token in a URL fragment is a different class of problem from a token in a request body
- How to find user-agent flow usage when it is not labelled as such
- What PKCE actually replaces, and why it makes the old flow unnecessary rather than merely safer
- Why two retirements on one date is the operational risk here
The Problem
The user-agent flow, called the implicit grant in the wider OAuth world, was designed for clients that cannot keep a secret. A single page app has no server side, so it cannot hold a client secret without publishing it. The implicit grant's answer was to skip the code exchange entirely: authenticate, and get the access token straight back in the redirect.
The token comes back in the URL fragment, after the #. Something like https://yourapp.example/callback#access_token=00D....
That location is the problem, and it is worth being precise about why, because "it is less secure" does not tell an admin what to look for. A URL fragment is recorded in browser history. It is available to any script running on the page, including anything a browser extension injects. It can end up in a shared link, or in a screenshot, or pasted into a ticket. None of that requires an attacker to break anything: the token is simply sitting where a lot of ordinary mechanisms can pick it up.
The hybrid user-agent flow has the same shape, returning a token alongside an identity assertion, and it goes for the same reason.
The wider industry reached this conclusion first. The implicit grant is gone from OAuth 2.1 and has been discouraged in browser-based app guidance for years. Salesforce retiring it on 20 February 2027 is the platform catching up with settled practice rather than making a novel judgement.
Quick Answer
Salesforce retires the OAuth user-agent flow and the hybrid user-agent flow on 20 February 2027. Any client that authenticates by requesting a token directly in the redirect, which is response_type=token or a hybrid variant returning a token in the URL fragment, stops working on that date. Move those clients to the OAuth web-server flow, or the hybrid web-server flow where an identity assertion is also needed, with the PKCE extension in both cases. PKCE is what makes the migration possible for public clients: it replaces the client secret with a per-request proof, so a single page app or mobile app can use the authorization code flow safely without embedding a secret. To find your exposure, review Connected Apps OAuth Usage in Setup, check which OAuth flows each connected app has enabled, and search your front end code for response_type=token. Note the same date carries the username-password flow retirement, which affects server to server integrations rather than browser ones, so both need checking.
Step 1: Find the clients, which are rarely labelled
The awkward part of this migration is that affected clients do not announce themselves. Nobody documents an internal tool as "the implicit grant one".
Three places to look, in increasing order of effort.
Connected Apps OAuth Usage in Setup. This lists connected apps that have actually been used to authenticate, which is a much shorter list than every app defined. Open each one and read its OAuth settings: the enabled flows and the callback URL tell you most of what you need.
Your own front end code. The signature is in the authorize request. Search for it:
grep -rniE "response_type=token|response_type=%20?token|responseType.*token" \
--include='*.js' --include='*.ts' --include='*.jsx' --include='*.tsx' \
--include='*.html' --include='*.cmp' --include='*.page' .
Include Visualforce pages and Aura components in that sweep. Older internal tools built inside the platform are a common home for this flow, and they are easy to forget precisely because they do not look like integrations.
Login History, for what is still live. Same grouped query shape as the other OAuth work, and the same trap:
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
On LoginHistory, Application, Status and ApiType are groupable but not filterable, so putting Application in the WHERE clause returns a parse error rather than a filtered list. Filter on LoginTime, UserId, LoginType, SourceIp or LoginUrl, and pick the rest out of the result.
Step 2: Understand what PKCE replaces
PKCE, Proof Key for Code Exchange, is the reason the web-server flow is now available to clients that could not use it before.
The authorization code flow was historically off limits to public clients because exchanging the code for a token required a client secret, and a browser app cannot hold one. PKCE removes that requirement. The client generates a random code_verifier, sends a hash of it as the code_challenge when it starts the flow, and presents the original verifier when it exchanges the code. Anyone who intercepts the code cannot use it without the verifier, which never left the client.
The practical consequence is the part worth carrying into a design discussion: the token never appears in a URL. It is returned in the response body of a back channel exchange, not in a fragment the browser records. That is the entire improvement, and it is why this is a migration rather than a workaround.
For clients that also need an identity assertion, the hybrid web-server flow is the equivalent destination, again with PKCE.
Step 3: Plan around the fact that two things enforce that day
This is the part most likely to go wrong, and it is not technical.
20 February 2027 carries two OAuth retirements, and they affect different systems:
| Retirement | Affects | Typical owner |
|---|---|---|
| Username-password (ROPC) | Server to server integrations, middleware, scheduled scripts | Integration or platform team |
| User-agent and hybrid user-agent | Browsers, single page apps, mobile, Canvas apps | Front end or app team |
An audit run by the integration team finds the middleware and reports the org clear. An audit run by the app team finds the front end and reports the org clear. Both are correct about their own half. Neither has looked at the other, and the org is not clear.
If you own the platform, the useful thing you can do is make sure one inventory covers both, rather than two inventories that each stop at a team boundary. The username-password retirement guide covers the other half in the same terms.
Frequently Asked Questions
Q: How is this different from the username-password retirement on the same date?
A: They fail for opposite reasons. Username-password passes a real user's credentials in a request body, so the problem is the credential. User-agent returns a token in the URL fragment, so the problem is where the token lands. They also affect different systems: one is server to server, the other is browser and mobile. The shared date is a coincidence of scheduling rather than a sign they are the same change, and treating them as one item is how half an estate gets missed.
Q: We use Lightning components, not a custom single page app. Are we affected?
A: Standard Lightning components running inside Salesforce authenticate through the platform session and are not doing an OAuth user-agent flow. What to check is anything hosted outside the platform that talks back to Salesforce: a Canvas app, an internal dashboard on your own domain, a mobile app, or a Visualforce page doing its own authorize request. The question is not which framework the UI uses, it is whether something outside Salesforce is obtaining a token from Salesforce.
Q: Can we keep the user-agent flow if the app is internal and behind SSO?
A: No. The retirement is a platform change, not a policy you can except an app from. Being internal also does not remove the exposure, since browser history, extensions and shared links behave the same way on an internal network as anywhere else.
Q: What breaks first if we do nothing?
A: Authentication, on 20 February 2027, for any client still using the flow. The failure is at login rather than mid-transaction, so there is no partial state to clean up. Whether anyone notices immediately depends on the client: a dashboard someone opens each morning surfaces it quickly, a mobile app with a long-lived refresh token might not fail until the refresh expires, which is worse because the fault arrives detached from the change.
Q: Is PKCE hard to add?
A: It is well supported in every current OAuth library, so for most clients it is configuration rather than code. The work in this migration is rarely PKCE itself. It is finding the affected clients, and then discovering that the one that matters most is a tool nobody owns any more.
Key Takeaways
- 20 February 2027 is a fixed date, shared with the username-password retirement, and the two hit opposite halves of an estate.
- The token in the URL fragment is the defect, which is why the fix is a different flow rather than tighter settings on this one.
- PKCE is what makes the web-server flow available to clients that cannot hold a secret, and it keeps the token out of the URL entirely.
- Affected clients are rarely labelled as integrations, so search front end code for
response_type=tokenrather than relying on an inventory. - One inventory should cover both retirements, because two team-scoped audits can each be correct and still miss half the problem.
What's Next?
Search your front end code for response_type=token today. It is a five minute check and it either ends the matter or gives you a list to work from.
If the list is not empty, pair this with the username-password retirement, since both enforce on 20 February 2027 and you want one view of the whole estate rather than two halves. For the wider release picture and the changes that are already enforced, see Salesforce Winter '27 Security Readiness, and for the nearest OAuth deadline of all, the device flow restriction on 30 November 2026.
Resources & References
- Salesforce Release Updates, under Scheduled to Be Enforced in 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 and with which flows.
- RFC 7636, Proof Key for Code Exchange, for the mechanism behind the replacement flow.
- The username-password flow retirement, which shares this date.
- The device flow restriction, enforced earlier on 30 November 2026.
Responses
Checking your session.
Loading responses.