Security & access

Salesforce OAuth username-password flow retirement: find and fix your integrations before 20 February 2027

By the orgadmin.ai team8 min read

On 20 February 2027 Salesforce stops supporting the OAuth 2.0 username-password flow for connected apps. Salesforce's own release note does not soften it: the update "will break all connected app integrations" that still use the flow. The same day, Salesforce also retires the OAuth user-agent and hybrid user-agent flows.

Most orgs have at least one integration that was set up years ago with a username, a password and a security token pasted into a config file. Nobody remembers it until it stops. This post shows how to find those integrations, test what breaks, and pick the right replacement for each one.

What exactly is being retired

There are two release updates, both enforced on 20 February 2027:

Release updateWhat it stopsWhat Salesforce says to use instead
Retirement of OAuth 2.0 Username-Password Flow for Connected AppsGetting a token by sending a username and password (grant_type=password) to the token endpointWeb-server flow with PKCE for users; client credentials flow for server-to-server
OAuth User-Agent and Hybrid User-Agent Flows RetirementFlows that hand the access token straight to the browserWeb-server or hybrid web-server flow with PKCE

A few details from the release notes that matter:

  • It applies to every edition, Lightning Experience and Classic.
  • The date has already moved once. The username-password retirement was announced in Spring '26 and first planned for Winter '27. Do not plan on a second delay.
  • New orgs are already blocked. Orgs created in Summer '26 or later cannot use the username-password flow at all. The setting is greyed out.
  • No release update means no work. If Retirement of OAuth 2.0 Username-Password Flow does not appear under Setup → Release Updates, the flow is already blocked in your org.
  • Packaged apps count too. For apps you did not build, including managed packages, Salesforce tells you to contact the app's developer.

Why Salesforce is doing it

The username-password flow sends a real user's credentials in an HTTP request. It skips MFA and SSO, and it means a password sits in plain text in some config file or environment variable. The user-agent flows have a different problem: they expose the access token to the browser. Both are older OAuth patterns that the rest of the industry has already left behind.

Step 1: find the integrations still using these flows

Every OAuth login is written to LoginHistory with a Login Subtype. The username-password flow shows up as OauthUsernamePassword. The user-agent flows show up as OauthUserAgent, OauthUserAgentIdToken and OauthHybridUserAgent.

Run this in the Developer Console, Workbench, the Salesforce CLI, or any SOQL tool:

SELECT LoginTime, UserId, Application, LoginSubType, SourceIp, Status
FROM LoginHistory
WHERE LoginSubType IN ('OauthUsernamePassword', 'OauthUserAgent',
                       'OauthUserAgentIdToken', 'OauthHybridUserAgent')
  AND LoginTime = LAST_N_DAYS:180
ORDER BY LoginTime DESC

Export the result and group it by Application and UserId. Each pair is one integration to fix. Source IP tells you where it runs: a cloud provider range, an office, or a server someone forgot about.

If you prefer clicks, open Setup → Login History and create a list view filtered on Login Subtype equals OAuth Username-Password.

Three things this check cannot tell you:

  1. Anything older than about six months. LoginHistory only keeps around six months, so a quarterly or annual job may not appear. Ask the owners of month-end, quarter-end and year-end processes directly.
  2. Integrations that have not logged in again. An integration holding a long-lived token may not show a fresh login for a long time. The retirement only bites when it asks for a new token.
  3. Which code is responsible. Search your repos, middleware and secrets stores for grant_type=password, "password grant" and "ROPC". Searching for /services/oauth2/token alone is not enough, because every OAuth flow uses that endpoint.

An empty result is good news, not proof. Combine it with the code search and a quick question to every team that owns an integration.

Step 2: test the break in a sandbox, not production

You do not have to wait for February to see what fails. In a sandbox, go to Setup → OAuth and OpenID Connect Settings and turn off Allow OAuth Username-Password Flows. To test the user-agent flows too, turn off Allow OAuth User-Agent Flows; Salesforce notes that this also blocks the hybrid app token flow.

An integration that still uses the flow will get an invalid_grant error saying authentication failure, and Login History records the attempt as blocked. Two cautions:

  • Cached tokens hide failures. An integration that already holds a valid token keeps working until it asks for a new one. Force a fresh token for each integration before you call it safe.
  • Sandboxes are not production. Some integrations only point at production. For those, test the new flow against a sandbox connected app first, then switch production in a planned window.

When everything is migrated, you can turn the same setting off in production before the deadline, so the date passes without surprises.

Step 3: choose the replacement flow

Pick the flow by asking one question: does a person sign in, or is it machine to machine?

Integration typeMove it toWhat changes
Middleware, ETL, scheduled jobs, data sync (no person signs in)Client credentials flowThe app gets a token with its consumer key and secret. It runs as a nominated Run As user. No refresh token is issued, so it simply asks for a new token when the old one expires.
Server-to-server where you want certificate-based trustJWT bearer flowThe app signs a JWT with a private key; Salesforce checks it against the certificate on the app. You now have a certificate to rotate.
Web or desktop apps where a real user signs inWeb-server flow with PKCEThe user signs in on Salesforce's own page (so SSO and MFA apply) and approves the app. The app never sees a password.
Single-page or mobile apps on the user-agent flowWeb-server or hybrid web-server flow with PKCETokens are no longer exposed in the browser URL.

For most old "integration user with a password" setups, client credentials is the shortest path. Enable it on the connected app or External Client App, set the Run As user, and change the integration to send grant_type=client_credentials.

Two traps to watch:

  • The Run As user decides what the integration can see. If you switch from the old integration user to a new one, check its object, field and record access before go-live. A permission gap here looks like missing data, not an error.
  • Moving to an External Client App is not the fix on its own. External Client Apps do not support the username-password flow at all, so the integration's code or configuration still has to change.

Step 4: tidy up while you are in there

This project is a rare moment when someone is looking at every integration at once. Use it:

  • Rotate the old password. Once an integration is on client credentials or JWT, the integration user's password is no longer needed. Rotate it so the old copy in that config file is useless.
  • Remove admin profiles from integration users. Many old integrations run as a System Administrator because it was easier. The Run As user only needs what the integration actually touches.
  • Revoke stale tokens. Tokens held by inactive users or not used in months are exactly the access nobody is watching.
  • Write down the owner. For each integration, record who owns it, which flow it uses and where its secret lives. Next time, this list is the audit.

Where orgadmin.ai helps

orgadmin.ai cannot change your integrations' code; that work stays with whoever owns them. It speeds up the finding and the clean-up:

  • Run the LoginHistory check in plain English. The SOQL Assistant writes and runs the query above against your live org, and exports the result to CSV so you can group it by application and user.
  • Clean up the access around integrations. The integrations module in the Security Review flags OAuth tokens held by inactive users, tokens unused for 90 days or more, broad OAuth scopes, and integration-style users with admin profiles.
  • Find the integration users. User Management lists every user with their profile and last login, so you can spot the integration accounts and who still needs a Run As user.

orgadmin.ai's own Salesforce connection uses the OAuth web-server flow, so this retirement does not affect it.

Checklist

  • Check Setup → Release Updates for both retirement updates (none listed = already blocked)
  • Run the LoginHistory query for the last 180 days and list each application + user pair
  • Search code, middleware and secrets for grant_type=password and user-agent flows
  • Ask owners of quarterly and yearly jobs, and every managed-package vendor, directly
  • In a sandbox, turn off the username-password and user-agent settings and force fresh tokens
  • Move server-to-server integrations to client credentials (or JWT), user-facing apps to web-server + PKCE
  • Check each Run As user's access, then rotate the old integration passwords
  • Turn the old flows off in production before 20 February 2027

Last checked 19 October 2026 against Salesforce's two release notes and the LoginHistory object reference. If Salesforce moves the date again, the steps stay the same.

Try it on your own org

orgadmin.ai puts an AI assistant, a security review and 21 more tools on your Salesforce org. 14-day free trial, no credit card.

Start free trial