afterbuild/ops
ERR-302/Google · GitHub · Supabase · Auth.js
ERR-302
OAuth callback URL not working in prod

appears when:user clicks 'Sign in with Google' in production — Google's error page shows, or the flow redirects to localhost.

OAuth callback URL not working in prod

Everything works locally. In production, the OAuth round-trip fails: either the provider rejects the redirect URI outright, or the flow loops back to localhost because Supabase's Site URL is still pointed there.

Last updated 17 April 2026 · 6 min read · By Hyder Shah
Direct answer

OAuth callback URL not working in production almost always means the production redirect URI is not whitelisted in the provider console. Google throws Error 400: redirect_uri_mismatch; GitHub throws redirect_uri MUST match the registered callback URL. Copy the exact URL from the error screen, paste it into Google Cloud → Credentials, set Supabase Site URL to your production domain, and add NEXTAUTH_URL to Vercel. Ten-minute fix.

Quick fix for OAuth callback URL not working in prod

auth/oauth-callback-fix.ts
typescript
01// 1. Google Cloud Console → Credentials → your OAuth Client02//    Authorized redirect URIs03https://<project-ref>.supabase.co/auth/v1/callback04https://yourapp.com/api/auth/callback/google05https://yourapp.com/auth/callback06 07// 2. Supabase Dashboard → Authentication → URL Configuration08Site URL:      https://yourapp.com09Redirect URLs: https://yourapp.com/**10               http://localhost:3000/**11 12// 3. Vercel → Settings → Environment Variables (Production)13NEXTAUTH_URL=https://yourapp.com14 15// 4. Client code — dynamic redirectTo, never hard-coded16await supabase.auth.signInWithOAuth({17  provider: 'google',18  options: { redirectTo: `${window.location.origin}/auth/callback` },19});
Paste provider, Supabase, Vercel, and client updates in order. Redeploy.

Deeper fixes when the quick fix fails

01 · Update every OAuth provider independently

Google, GitHub, and Apple maintain separate allowlists. A fix in Google Cloud does not affect GitHub. Update each provider console with the same set of production, staging, and localhost URLs.

providers.md
text
01Google — Cloud Console → APIs & Services → Credentials → OAuth 2.0 Client IDs02GitHub — Settings → Developer settings → OAuth Apps → your app → Authorization callback URL03Apple — developer.apple.com → Certificates, IDs & Profiles → Services IDs → Return URLs

02 · Strip trailing slashes and normalize www vs apex

Providers do byte-equal string matching. https://yourapp.com and https://www.yourapp.com are different origins. Pick a canonical host, redirect the other, and add only the canonical version to each provider.

03 · Fix NEXTAUTH_URL on Vercel (Auth.js specific)

Auth.js builds its callback URL from NEXTAUTH_URL. Without it, Auth.js infers the URL from incoming request headers, which on Vercel includes the internal edge runtime hostname, not your public domain. The symptom looks like a provider mismatch but the cause is an environment variable.

04 · Search the repo for hard-coded localhost URLs

Generators hard-code redirectTo: 'http://localhost:3000' in the first OAuth scaffold. Every other fix holds until this string ships to production — then the flow breaks silently because the redirect_uri sent to the provider is literally localhost.

scripts/check-oauth.sh
bash
01# Run pre-deploy — block any commit that hard-codes localhost OAuth redirects02grep -rn "redirectTo:.*localhost" src/ && {03  echo "hard-coded OAuth redirect found — use window.location.origin"04  exit 105}

Why AI-built apps hit OAuth callback URL not working in prod

Lovable, Bolt, and v0 scaffold OAuth by calling supabase.auth.signInWithOAuth with a redirectTo pointed at the preview URL. That preview URL is allowlisted in the auto-provisioned Supabase project and sometimes even added to the generator's shared Google OAuth client. Everything works in preview. The moment the app is deployed to a real domain, none of those entries match — the production URL is not in Supabase's allowlist, not in Google's allowlist, and not in the hard-coded redirectTo the generator emitted.

The failure is loud in the browser (the user lands on Google's error page) but silent in logs. Your app never runs because the redirect never returns — Google halts the flow with a 400 before calling back. There is no Vercel function invocation to grep, no Supabase log entry to inspect. Founders often spend an hour searching for a bug in their callback route before realizing the callback route was never reached.

The third layer of pain is NEXTAUTH_URL. Auth.js needs this env var to build its own callback URL; without it, Auth.js infers the URL from the incoming request headers, which on Vercel includes the internal edge runtime hostname, not your public domain. The symptom looks identical to a redirect URI mismatch but the cause is an environment variable — which is why the same fix patterns appear repeatedly: touch every allowlist, touch every environment variable, and make every client-side redirect dynamic.

OAuth callback URL not working in prod by AI builder

How often each AI builder ships this error and the pattern that produces it.

AI builder × OAuth callback URL not working in prod
BuilderFrequencyPattern
LovableVery highHard-codes redirectTo to Lovable preview URL; production apex never registered.
Bolt.newHighUses bolt.new sandbox redirect URI; custom-domain URL never propagated.
v0HighShips Auth.js without NEXTAUTH_URL; callback URL built from Vercel edge hostname.
CursorMediumWrites dynamic redirectTo but forgets to update Supabase Site URL from localhost.
ReplitMediumLeftover replit.dev preview URL in provider allowlist shadows production host.
Claude CodeLowCorrect runtime code but missing documentation on which providers to update per deploy.
WindsurfLowUpdates Google but not Supabase — flow bounces back to localhost after provider approves.
Base44MediumCustom-domain added in Base44 UI but never synced to Google Cloud or Supabase.

Related errors we fix

Stop OAuth callback URL not working in prod recurring in AI-built apps

Still stuck with OAuth callback URL not working in prod?

Emergency triage · $299 · 48h turnaround
We restore service and write the root-cause report.

Get OAuth flowing across every environment — we touch all four layers.

  • Provider allowlists, Supabase Site URL, NEXTAUTH_URL, and client code aligned in one pass
  • Verified in an incognito smoke test before handover
  • Shipped with a documented per-environment URI list for your team
start the triage →

OAuth callback URL not working in prod questions

Why does my OAuth callback work on localhost but fail in production?+
Because OAuth providers enforce an exact-match allowlist of redirect URIs, and your provider (Google, GitHub, or Supabase) only has the localhost URL registered. The provider rejects the callback with redirect_uri_mismatch before your app is ever invoked. You need to add the exact production URL to the provider's allowlist and update any app-side redirectTo value that still hard-codes localhost.
What does the error redirect_uri_mismatch actually mean?+
It means the redirect URI your app sent to Google (or GitHub) does not appear in the list of Authorized redirect URIs registered for that OAuth client. Google compares strings byte-for-byte: https://yourapp.com and https://www.yourapp.com are different, http://yourapp.com and https://yourapp.com are different, and trailing slashes matter. Copy the URL from the error screen exactly and paste it into the provider console — that is the URL you need to allow.
Do I have to update Supabase too, or just the OAuth provider?+
Both. Supabase has its own 'Site URL' and 'Redirect URLs' allowlist that is separate from Google's. If Supabase's Site URL still points to localhost, Supabase rewrites the final redirect back to localhost even after Google approves the sign-in. Set the Site URL to your production domain and add both production and localhost to the Redirect URLs list so local dev keeps working.
How do I handle OAuth callback URLs for multiple environments?+
Register each environment's URL in the provider console. Google supports up to 100 redirect URIs per OAuth client, so add staging, production, and localhost all to the same client. On the app side, derive the redirectTo from window.location.origin rather than hard-coding a string — that way the same code works on every environment without changes. For server-side flows, read from NEXTAUTH_URL or an equivalent env var.
How long does fixing an OAuth callback URL take?+
Ten to fifteen minutes if you have admin access to the OAuth provider console, Supabase, and Vercel environment variables. The actual change is a copy-paste of URLs. Most of the time is spent waiting for a Vercel redeploy after you update NEXTAUTH_URL or the client-side redirect. If something else is wrong — a proxy stripping headers, a middleware rewriting the callback path — budget an extra hour for diagnosis.
Next step

Ship the fix. Keep the fix.

Emergency Triage restores service in 48 hours. Break the Fix Loop rebuilds CI so this error cannot ship again.

About the author

Hyder Shah leads Afterbuild Labs, shipping production rescues for apps built in Lovable, Bolt.new, Cursor, Replit, v0, and Base44. our rescue methodology.

OAuth callback URL not working in prod experts

If this problem keeps coming back, you probably need ongoing expertise in the underlying stack.

Sources