An OAuth redirect URI mismatch means the callback URL in an authorization request does not match what the identity provider expects for that client. A trailing slash, a different scheme or port, or incorrect percent encoding can be enough to cause the error.
This guide shows how to compare the registered callback with the value actually sent, identify common differences, and fix the configuration without weakening redirect validation. No provider is specified here, so provider-specific registration rules and console settings should be checked in that provider’s current documentation.
Key Takeaways
- Compare the registered redirect URI with the decoded
redirect_uriparameter sent in the authorization request. - Treat the callback as an exact string unless your provider’s documentation says otherwise; don’t assume two similar-looking URLs are interchangeable.
- Check the scheme, hostname, port, path, trailing slash, and any query string.
- Encode the callback once when placing it inside the authorization request URL. Don’t confuse that outer encoding with percent encoding that is part of the callback itself.
- Don’t “fix” a mismatch by allowing broad, unvalidated callback patterns. Redirect URI validation helps prevent authorization codes from being sent to an attacker-controlled destination.
What an OAuth redirect URI mismatch means
In an authorization-code flow, your application sends the user to the provider’s authorization endpoint. The request includes a redirect_uri: the callback where the provider should return the user after authorization. The provider checks that value against the redirect URIs registered for the client.
For example, the provider may have this URI registered:
https://app.example.com/oauth/callback
But the application may send:
https://app.example.com/oauth/callback/
The only difference is the final slash, but the provider may treat these as different strings. A mismatch usually indicates inconsistent configuration between the provider’s client settings and the application environment—not a problem with the user’s credentials.
OAuth providers can impose provider-specific rules, such as restrictions on development URLs or accepted URI patterns. General OAuth guidance is not a substitute for the documentation for the provider and client type you are using.
Compare the registered and requested callback URLs
First find the exact redirect URI registered for the relevant OAuth client. Then inspect the authorization request sent by your application and extract its redirect_uri value. Compare those two values—not the full authorization request URL.
Example authorization request:
https://login.example-idp.test/authorize?response_type=code&client_id=demo-client&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback&state=example-state
The redirect_uri parameter in that request decodes to:
https://app.example.com/oauth/callback
You can extract it in JavaScript with the built-in URL API:
const authorizationUrl = new URL(
"https://login.example-idp.test/authorize?response_type=code&client_id=demo-client&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback&state=example-state"
);
const sentRedirectUri = authorizationUrl.searchParams.get("redirect_uri");
const registeredRedirectUri = "https://app.example.com/oauth/callback";
console.log({
sentRedirectUri,
matches: sentRedirectUri === registeredRedirectUri,
});
The expected result is matches: true. Replace the example values with your own, and compare the decoded request parameter to the URI registered for the same client and environment. This check is diagnostic; it does not replace your provider’s validation.
Check each part of the URI
Compare the values character by character, paying particular attention to these differences:
| Part | Registered URI | URI sent in request | Possible difference |
|---|---|---|---|
| Scheme | https://app.example.com/callback | http://app.example.com/callback | HTTPS versus HTTP |
| Port | https://app.example.com/callback | https://app.example.com:8443/callback | Explicit port differs |
| Path | https://app.example.com/oauth/callback | https://app.example.com/auth/callback | Different path |
| Trailing slash | https://app.example.com/callback | https://app.example.com/callback/ | Final slash added |
| Query string | https://app.example.com/callback?tenant=blue | https://app.example.com/callback?tenant=green | Query value differs |
Scheme and port
A local app might send http://localhost:3000/callback while the provider has http://localhost:5173/callback registered. The port is part of the URI and can distinguish local development servers. Production may use a separate HTTPS callback, so check which client configuration your running environment actually uses.
Path and trailing slash
Check the callback route used by your application framework and the URI saved in the provider console. Don’t assume a server will redirect between /callback and /callback/ before the provider performs its comparison.
Query strings
If the registered callback includes a query string, compare its keys and values as well. Avoid relying on a provider to ignore, reorder, or otherwise normalize query parameters unless its documentation explicitly describes that behavior. Keep the callback as simple as your integration permits.
Percent encoding
The authorization request is itself a URL, so the callback’s characters must be encoded when it is placed in the outer redirect_uri parameter. For example, the colon and slashes in https://app.example.com/oauth/callback appear encoded in the request as %3A and %2F.
Decode the outer parameter once to recover the callback value before comparing it. Don’t compare the encoded outer representation with the plain registered URI, and don’t encode the entire authorization URL again. If the callback itself contains percent-encoded characters, those may be part of its value; don’t decode them repeatedly or normalize them casually.
A practical troubleshooting sequence
- Select the right OAuth client. Confirm that the client ID in the request belongs to the environment and application you are inspecting.
- Copy the registered URI. Take it from the provider’s client configuration rather than reconstructing it from memory.
- Inspect the outgoing authorization request. In browser developer tools or safe application diagnostics, locate the
redirect_uriparameter. - Decode the parameter once. Use a URL parser or the
URLAPI to read the parameter value. - Compare exact values. Check scheme, host, port, path, slash, query string, and percent-encoded characters.
- Check configuration sources. Look for environment variables, framework defaults, proxy settings, or separate development and production configuration that may be building a different callback.
- Update the correct side. Make the application send the intended registered URI, or register the intended callback using the provider’s documented process.
- Retry the flow. Verify that the authorization request now contains the expected callback and that the provider accepts it.
When inspecting requests or logs, avoid sharing access tokens, authorization codes, client secrets, or personal data. The callback URI is usually enough to diagnose this error; redact unrelated parameters before posting a request publicly.
Keep redirect URI handling safe
A redirect URI is security-sensitive: the provider may return an authorization code to that destination. If an application accepts arbitrary callback URLs, an attacker may be able to redirect a response to a destination they control. Exact registration and validation help limit that risk.
Register only the callbacks your application needs. Avoid wildcard patterns or loose prefix checks unless the provider explicitly supports them and you understand their security implications. For example, a check that accepts every URL beginning with https://app.example.com might also accept a deceptive hostname such as https://app.example.com.attacker.test if implemented as a naive string prefix test.
If your application chooses a callback based on a user-controlled value, map an approved identifier to a fixed, preconfigured URI. Don’t accept an arbitrary URL and treat successful parsing as proof that it is safe. Follow your provider’s documented rules, and validate the callback at the point where your application creates the authorization request.
Common Mistakes
- Comparing the wrong strings. Compare the registered URI with the decoded
redirect_uriparameter, not with the whole authorization endpoint URL. - Ignoring environment differences. A local callback, staging callback, and production callback may use different hosts or ports.
- Adding a slash to make a route work. A web server’s route behavior does not guarantee that the provider considers two callback strings equivalent.
- Double-encoding the callback. This can make the provider receive an encoded string rather than the intended URI.
- Assuming every query parameter is irrelevant. A query string can be part of the callback and affect the value being compared.
- Allowing any callback to avoid the error. Broad or unvalidated patterns can weaken a security boundary instead of fixing the configuration.
Best Practices
- Keep a clear, environment-specific list of registered callback URIs.
- Use the provider’s current documentation for its exact-match rules and client-type restrictions.
- Construct the authorization request from one trusted configuration value rather than duplicating callback strings in multiple places.
- Compare the decoded callback value during debugging, but avoid changing or canonicalizing it unless the provider documents that behavior.
- Keep callbacks minimal and fixed where possible, and never use an untrusted user-supplied URL as the redirect destination.
Conclusion
An OAuth redirect URI mismatch is usually a small difference between the callback registered with the provider and the value sent by the application. Extract and compare the decoded redirect_uri, check each URI component, and correct the configuration without loosening validation. For rules specific to your identity provider, use its current documentation.
