Rescue · Auth

OAuth Redirecting to Localhost? Here’s the Fix

Sign-in works on your machine, but on the real domain Google bounces users to localhost:3000 — or throws redirect_uri_mismatch. This is the most common auth failure in AI-built apps, and the fix lives in three places at once.

Impact: users can’t sign inFix effort: hoursThree configs to align
Symptoms

The shapes this bug takes

Browser lands on localhost:3000

The OAuth flow completed — then sent the user to a URL that only exists on the developer’s machine. Classic frozen-at-prompt-time config.

redirect_uri_mismatch from Google

The provider refused before starting: the redirect your app requested isn’t on its allowlist. The production callback was never registered.

Password reset emails link to localhost

Same root cause, different door: reset links are built from the auth layer’s Site URL, which still points at dev.

Works for you, broken for everyone else

The cruellest variant — the developer is on localhost, so the bug is invisible until a real user hits it.

The AI configured what it could see

When the app was generated, the only URL in existence was the dev preview. Every redirect URI, site URL and callback got set to it — and nothing forces an update at deploy time.

Three configs must agree

The OAuth provider (Google/GitHub console), your auth layer (Supabase Auth settings), and the app's own environment variables each hold a copy of the redirect URL. Any one still saying localhost breaks the chain.

Auth only breaks off the happy path

Sign-in on the dev machine is the happy path. Fresh browser, new device, expired session, reset flow — that's where the frozen config surfaces.

## The three places to fix, in order
# 1. Provider console (Google Cloud / GitHub OAuth app)
Authorized redirect URI → https://YOUR-PROJECT.supabase.co/auth/v1/callback
Authorized origins → https://www.yourdomain.com
# 2. Supabase → Authentication → URL Configuration
Site URL → https://www.yourdomain.com + add it to Redirect URLs
# 3. The codebase: no literal URLs
grep -rn "localhost" src/ # every hit is a future bug

Then prove it works

01

Fresh Browser Test

Incognito window, production URL, an account that has never signed in. The developer's browser proves nothing.

02

Every Provider You Offer

Google, GitHub, email links — each has its own callback registration. Fixing one doesn't fix the others.

03

The Reset Flow

Trigger a real password reset and click the emailed link. It's built from Site URL and breaks in sympathy.

04

Session Lifecycle

Sign out, expire a session, revoke access — the paths that only run in production deserve one deliberate pass.

FAQ

Common questions

I changed the Google console but it still redirects wrong. Why?

Because Supabase's own Site URL and redirect allowlist is the second gate, and the deployed app's env vars are the third. All three must agree — check them in that order.

Password reset emails link to localhost too. Same fix?

Same root cause — those links are built from the Site URL setting. Fix it, then run a real reset end to end in production.

Can I keep localhost in the allowlists for development?

Yes — allowlists take multiple entries; add production alongside localhost rather than replacing it. Just make sure Site URL points at production, since it's the default fallback.

Is this worth hiring someone for?

If this guide gets you through, no. If auth has several broken paths at once — resets, sessions, roles — that usually signals wider config drift, which is what the $299 triage maps in 48 hours.

Keep reading

Related rescue guides

$299 triage · 48 hours · credited against any fix

Auth that works on every domain

We fix the full auth surface — OAuth, sessions, resets, roles — inside every rescue sprint.

43+ happy clients · rated 4.9/5 · senior engineers on every build