Fix OAuth redirect_uri_mismatch when testing auth on localhost dev
The problem
Local dev login bounced back from the provider with Error 400: redirect_uri_mismatch. The provider requires an https:// redirect URI, so http://localhost:3000/auth/callback can't be registered — and without a code, the token exchange never happens.
What didn't work
- Adding
http://localhost:3000to the provider console anyway — rejected because the URI scheme isn't https. - Changing the callback route path to "match" — the provider compares the full URI byte-for-byte, so
/auth/callbackvs/callbackor a trailing slash is a mismatch, not a near-miss. - Pointing the redirect at the production URL from dev — the code lands on prod's cookie jar and your local session is still anonymous.
The fix
Get a stable public https hostname that proxies to your dev server, then register BOTH exact callback strings:
# one command, no account needed:
cloudflared tunnel --url http://localhost:3000
# => https://something-random-words.trycloudflare.com
// lib/auth.ts
const DEV_HOST = 'https://something-random-words.trycloudflare.com'; // from the tunnel output
const REDIRECT_URI =
process.env.NODE_ENV === 'production'
? 'https://app.example.com/auth/callback'
: `${DEV_HOST}/auth/callback`;
// register BOTH exact strings in the OAuth console:
// no trailing slash, identical path, identical scheme
For a hostname that survives restarts, create a named tunnel: cloudflared tunnel create dev-auth, map it to dev-auth.example.com, and run cloudflared tunnel run dev-auth alongside the dev server.
Why it works
The tunnel terminates TLS on a public hostname while proxying to your local port, so the browser and provider both see an https redirect_uri that matches the console registration exactly — which is the literal string comparison the provider performs before issuing the authorization code.