Salesforce OAuth failures split into two groups that look similar and are fixed in completely different places. Errors returned by the authorization or token endpoint, such as invalid_grant and redirect_uri_mismatch, are configuration problems in the OAuth app. INVALID_SESSION_ID, returned by an API call, is a token lifecycle problem in your client.
Getting that split right saves the afternoon. Nobody has ever fixed INVALID_SESSION_ID by editing callback URLs, and plenty of people have tried.
Start here: which kind of error is it?
| Where the error came back | What it is | Where the fix lives |
|---|---|---|
| The /services/oauth2/authorize or /services/oauth2/token endpoint | An OAuth error | Your app configuration or the request you sent |
| Any API call, after you already had a token | A session or permission error | Your token handling, or the user's access |
The OAuth errors Salesforce documents
| Error | What Salesforce says | What it usually means in practice |
|---|---|---|
| invalid_grant | Many causes: invalid authorization code, invalid credentials, invalid user, invalid assertion, invalid audience, IP restrictions, code_verifier issues, missing user approval, authentication failure, expired tokens | The catch-all. Work through the list below |
| redirect_uri_mismatch | Redirect URI mismatch with the app definition | A trailing slash, http instead of https, or the wrong environment's callback |
| redirect_uri_missing | Redirect URI not provided | The parameter was dropped, often by a proxy |
| invalid_client_id | Client identifier is invalid | Wrong client ID, or a key copied with whitespace |
| invalid_client | Client secret is invalid | Wrong or rotated secret |
| invalid_request | HTTPS is required, HTTP GET or POST is required, invalid code_challenge, unsupported parameters, invalid device code | A malformed request rather than bad credentials |
| invalid_scope | The requested scope is invalid, unknown or malformed | Asking for a scope the app was not granted |
| invalid_app_access | User isn't approved by an admin to access this app | App policy is set to admin-approved users only |
| inactive_user | User is set to inactive by the org's admin | Someone deactivated the integration's user |
| inactive_org | Org is locked, closed or suspended | Nothing you can fix in code |
| access_denied | User denied access to the client app | The user clicked Deny |
| rate_limit_exceeded | Number of login attempts has been exceeded | Retry storm, usually your own |
| server_error | The number of authorization requests from the client app exceeds the hourly limit | You are re-authorizing in a loop |
| CSRF | A possible cross-site request forgery was detected | The login request did not come from the expected domain |
| No_OAuth_State | The OAuth state was tampered with or is missing | State lost across a redirect |
| immediate_unsuccessful | immediate is true and the user is not logged in or has not previously approved access | Expected, when using immediate mode |
| authorization_pending | Device flow, the user has not approved yet | Keep polling |
| slow_down | Device flow, you are polling more often than the recommended interval | Back off |
| unsupported_response_type | Requested response type isn't supported | Wrong response_type for the flow |
| NO_ACCESS | Unable to find a user | No matching user, for example no username |
| ERROR_CREATING_USER | Username not unique, a contact exists for the email, the user lacks a licence, or a storage limit was exceeded | Just-in-time provisioning failed |
| REGISTRATION_HANDLER_ERROR | A problem with your registration handler Apex code | Your handler threw |
| No_Openid_Response | User Info Endpoint URL is invalid | Auth provider misconfiguration |
| invalid_assertion_type | Specified assertion type isn't supported | Wrong assertion mechanism |
Working through invalid_grant
invalid_grant covers the most ground, so it needs a checklist rather than a fix. Work down it in this order, because the top entries are the most common and the cheapest to test.
- Is the refresh token expired or revoked? Check the app's Refresh Token Policy under Policies, then OAuth Policies, then App Authorization. If it is set to expire and your integration is long-lived, this is the answer. "Refresh token is valid until revoked" is the setting long-running integrations want.
- Was the authorization code already used? Codes are single use and short lived. A retry that replays the same code fails here.
- Did an admin revoke the app? Revoking access in Setup invalidates every issued token, and the failure looks identical to expiry.
- Is there an IP restriction? IP relaxation settings on the app can reject a token request from an address that was fine last week, which is what happens when a cloud provider rotates egress IPs.
- Is PKCE mismatched? A
code_verifierthat does not match thecode_challengeyou sent producesinvalid_grant, not a PKCE-specific error. - Does the user still exist and still have access? An inactive user or a removed permission set assignment lands here too.
If the app issues JWT-based access tokens, the hybrid app refresh token flow returns invalid_grant on a token request. Refresh token rotation in that flow is supported only with opaque access tokens, so the fix is the token format rather than anything about the request.
Fixing redirect_uri_mismatch
The single most common OAuth failure, and the error text never tells you which part differs. Salesforce compares the redirect URI on the request against the stored value character for character.
The four differences that cause it, in rough order of frequency:
- A trailing slash on one side and not the other
httpwhere the app hashttps- The callback for a different environment, staging against production
- A URL retyped by hand rather than copied
Copy and paste, always. Add every environment's callback to the same app rather than keeping several apps in step, since redirect URLs stay editable after creation.
INVALID_SESSION_ID is a different problem
This one comes back from an API call, not from the token endpoint, and it means the access token you presented is no longer valid.
| Cause | Fix |
|---|---|
| The access token expired | Refresh it. Expected behaviour, not a fault |
| Session timeout on the org reached | Refresh, and check the session settings if it happens sooner than expected |
| The app or token was revoked | Re-authorize |
| You called the wrong instance URL | Use the instance_url returned with the token, not a hardcoded host |
That last row is worth checking first when the error appears on a connection that has never worked. Salesforce returns instance_url alongside the access token precisely so you do not have to guess, and a hardcoded login.salesforce.com for API calls produces exactly this error.
The right pattern is to treat INVALID_SESSION_ID as a normal signal rather than an exception: catch it, refresh once, retry the call once, and only then surface a failure. Integrations that instead refresh proactively on a timer end up doing both, and are the ones that trip rate_limit_exceeded.
One unexpected cause of invalid_client_id
Nango's Salesforce troubleshooting documents a cause that is worth knowing before it costs you a day: this error can be produced by the developer user's password containing special characters. If the client ID is definitely correct and the request still fails, that is the thing to check.
Preventing most of this
Three configuration choices remove the majority of recurring OAuth failures.
Set the Refresh Token Policy deliberately. Under Policies, then OAuth Policies, then App Authorization. Leave it on a short expiry and your integration will keep dying on a schedule nobody connects to a setting.
Add every environment's callback to one app. Cheaper than keeping several apps in step, and it removes the whole class of staging-versus-production mismatches.
Use an external client app for anything new. Connected app creation through the UI was turned off by default on new orgs in Winter '26, and re-enabling it has required Salesforce Support since Spring '26. Existing connected apps keep working, and App Manager offers a migration path for eligible ones.
If you need one provisioned rather than built by hand, Appnigma's external client app provisioner issues the client ID, secret and a managed package install link.
Frequently Asked Questions
What causes invalid_grant in Salesforce?
Salesforce documents many causes under one code: an invalid or already-used authorization code, invalid credentials, an invalid user or assertion, IP restrictions, a mismatched code_verifier, missing user approval, and expired tokens. The most common in production is an expired or revoked refresh token, which is controlled by the app's Refresh Token Policy.
How do I fix redirect_uri_mismatch in Salesforce?
Make the callback URL on the Salesforce app match the one your client sends, character for character. The usual differences are a trailing slash, http instead of https, or a callback copied from a different environment. Copy and paste the value rather than retyping it, and add every environment's callback to the same app.
What does INVALID_SESSION_ID mean?
The access token presented on an API call is no longer valid, usually because it expired, the session timed out, or access was revoked. It can also mean you called the wrong host, so always use the instance_url returned with the token rather than a hardcoded login domain. Handle it by refreshing once and retrying once.
Why does my Salesforce refresh token keep expiring?
Because the app's Refresh Token Policy is set to expire. Change it under Policies, then OAuth Policies, then App Authorization. For long-lived integrations, "Refresh token is valid until revoked" is the setting you want.
Is INVALID_SESSION_ID an OAuth error?
No. OAuth errors come back from the authorization or token endpoint and point at app configuration. INVALID_SESSION_ID comes back from an API call and points at token lifecycle handling in your client. They are fixed in different places.
What causes rate_limit_exceeded on Salesforce OAuth?
The number of login attempts has been exceeded. In practice it is almost always a retry loop in your own integration, often one that refreshes proactively on a timer as well as reactively on failure. Refresh on failure only.
Can I still create a connected app in Salesforce?
Existing connected apps keep working, but creation through the UI was turned off by default on new orgs in Winter '26, and re-enabling it has needed approval from Salesforce Support since Spring '26. New integrations should start with an external client app.
Related Articles
- What is an external client app in Salesforce
- Connected app vs external client app compared
- OAuth authentication in Salesforce
- Salesforce external client app OAuth flows
Sources
- Salesforce Help, OAuth 2.0 Authorization Errors: the documented error codes and descriptions quoted above. 2/ Salesforce Help, OAuth 2.0 Hybrid App Refresh Token Flow: JWT-based access tokens and refresh token rotation. 3/ Salesforce Help, Invalid Session ID knowledge articles and External Client Apps. 4/ Nango Docs, Salesforce troubleshooting: developer password special characters as a cause of invalid client ID. 5/ Appnigma, external client app product flow verified 2 September 2026.



