2026-06-22 · 6 min read · Rahul Chitturi
- oauth
- auth
- debugging
Few OAuth errors are as frustrating as redirect_uri_mismatch. The app is registered, the login page opens, and then the provider rejects the callback because one byte of the redirect URI is different from what it expected.
The fix is rarely a code rewrite. Most incidents come down to exact string comparison: scheme, host, path, trailing slash, port, query encoding, and which environment is calling the identity provider.
Compare the full redirect URI
OAuth providers compare the redirect URI as an exact registered value. https://app.example.com/callback, https://app.example.com/callback/, and http://app.example.com/callback are different strings. Local development ports and preview deployment hosts also count.
- Scheme: http in local dev versus https in staging or production
- Host: apex domain, www domain, preview URL, or localhost
- Path: /callback, /auth/callback, or framework-specific route
- Trailing slash: some providers treat it as a different URL
- Port: localhost:3000 is not the same as localhost:5173
Encode only the values that need it
The redirect_uri parameter itself must be URL-encoded when it appears inside an authorization URL. But encoding the whole authorization URL, or encoding the same redirect URI twice, can produce a value the provider has never seen.
Decode the received value, compare it with the registered callback, then encode it once as a query parameter. This catches spaces, plus signs, nested return URLs, and copied ampersands before they reach production.
Separate environment and app registration bugs
A production client ID with a staging callback fails the same way as a typo. So does a staging secret paired with a production issuer. Before changing application code, confirm that the client ID, issuer, redirect URI, and deployment host all belong to the same environment.
- Keep provider app registrations named by environment
- Store callback URLs beside the client ID in config docs
- Log the final authorization URL in non-production only
- Redact client secrets and one-time authorization codes from tickets
Check the token path after callback
After the redirect mismatch is fixed, a second failure can appear during token exchange. Decode test JWTs to confirm issuer, audience, expiration, and tenant claims. Do not treat decoded claims as authorization in production; verification must still happen server-side.
When two environments behave differently, diff the authorization URL, token request body, and decoded non-secret claims side by side. That usually exposes the drift faster than stepping through framework middleware.
A Flashman workflow
Flashman's tools run in the browser, which is helpful when OAuth data includes sensitive hosts, tenants, and tokens. Use fake or non-production values when possible, and clear the tab when the debugging session is done.
- Use the URL encoder/decoder to inspect redirect_uri once, not twice
- Format provider JSON errors so the real field names are readable
- Decode non-production JWTs to inspect issuer, audience, and expiration
- Diff working and failing authorization URLs before editing code