Error 400: redirect_uri_mismatch
appears when:clicking 'Sign in with Google' from production — Google halts on a 400 screen before your callback runs.
Google OAuth redirect_uri_mismatch
Google compared the redirect URI your app sent with the Authorized redirect URIs on your OAuth 2.0 Client and found no exact match. The browser lands on a 400 page, your callback route never runs, and logs stay empty.
Error 400: redirect_uri_mismatch means the redirect_uriyour app sends is not in the Authorized redirect URIs list on the matching OAuth 2.0 Client. Copy the exact URL from the error screen, open Google Cloud Console → APIs & Services → Credentials → your client, paste into Authorized redirect URIs, save. Five-minute fix. If it persists, the client_id your app sends refers to a different OAuth client than the one you edited.
Quick fix for Google OAuth redirect_uri_mismatch
01// Google Cloud Console → APIs & Services → Credentials02// Open the OAuth 2.0 Client whose ID matches GOOGLE_CLIENT_ID.03// Add every environment you deploy to (up to 100 URIs per client):04 05https://yourapp.com/api/auth/callback/google06https://yourapp.com/auth/callback07https://<project-ref>.supabase.co/auth/v1/callback08https://staging.yourapp.com/api/auth/callback/google09http://localhost:3000/api/auth/callback/google10 11// Click Save. Changes propagate in ~1 minute.12// Retry sign-in in an incognito window.Deeper fixes when the quick fix fails
01 · Confirm you are editing the right OAuth client
With multiple Google Cloud projects, it is easy to edit a client whose client_id the app never sends. Open devtools → Network, click the sign-in button, inspect the request to accounts.google.com/o/oauth2/v2/auth, and copy the client_id query param. The client you edit in Google Cloud Console must have that exact ID.
02 · Derive redirect_uri from the current origin
Hard-coded redirect URIs are the root cause of environment drift. Use window.location.origin in the browser or NEXTAUTH_URL on the server so the same code works everywhere without new allowlist entries per deploy.
01// Bad — breaks on every new environment02await supabase.auth.signInWithOAuth({03 provider: 'google',04 options: { redirectTo: 'http://localhost:3000/auth/callback' },05});06 07// Good — one line, works on localhost, staging, production08await supabase.auth.signInWithOAuth({09 provider: 'google',10 options: {11 redirectTo: `${window.location.origin}/auth/callback`,12 },13});03 · Strip trailing slashes and protocol drift
https://yourapp.com/auth/callback and https://yourapp.com/auth/callback/ are different strings to Google. http:// vs https:// are different. www vs apex are different. Copy the URL from the error screen verbatim — never retype it.
04 · Update 'Authorized redirect URIs', not 'JavaScript origins'
Authorized JavaScript origins controls where Google's sign-in library can be initialized. It does not affect the server-side redirect. redirect_uri_mismatch is always about Authorized redirect URIs — a separate field on the same OAuth client page.
Why AI-built apps hit Google OAuth redirect_uri_mismatch
Lovable, Bolt, and Cursor all generate Google OAuth integrations with a single redirect URI — the preview URL their sandbox is running on. The generator adds that URI to the Google Cloud project via an automated setup, if it manages one at all. The moment you deploy to a real domain, the preview URI no longer matches the redirect_uri your code sends, and Google throws Error 400. The fact that this fails outside your app is the critical signal: Google halts the OAuth flow server-side, so there is no Vercel log entry to debug, no Supabase log to inspect — just a browser that lands on Google's error page.
The second trap is client_id drift. When you move from a generator- managed Google project to your own, the GOOGLE_CLIENT_ID env var in your app points at a different OAuth client than the one you are viewing in Google Cloud Console. You can spend an hour adding URIs to the wrong client and making no progress. The fix is to copy the client_id query parameter from the URL during sign- in and open the matching client in Google Cloud, not the first one you find.
The third trap is trailing slashes and protocol drift. https://yourapp.com/auth/callback and https://yourapp.com/auth/callback/ are different strings to Google. http:// vs https:// are different. www vs apex are different. Founders paste a URL from memory, miss the terminal slash, see the error continue, and conclude that Google is broken. The error screen always contains the exact value to paste; copy it verbatim.
Google OAuth redirect_uri_mismatch by AI builder
How often each AI builder ships this error and the pattern that produces it.
| Builder | Frequency | Pattern |
|---|---|---|
| Lovable | Very high | Supabase OAuth preview URL wired to shared Google client; breaks on first custom domain. |
| Bolt.new | High | Hard-codes redirectTo to bolt.new preview host; production URL never allowlisted. |
| v0 | High | Auth.js scaffolded with NEXTAUTH_URL unset — callback URL built from edge hostname. |
| Cursor | Medium | Generator emits redirectTo without trailing-slash normalization. |
| Replit | Medium | Leftover replit.dev preview URI in Authorized redirect URIs; production apex missing. |
| Claude Code | Low | Correct dynamic redirect but forgets to document the new Authorized URI per deploy. |
| Windsurf | Low | Edits Authorized JavaScript origins instead of Authorized redirect URIs. |
| Base44 | Medium | Production custom domain added in Base44 but never propagated to Google Cloud. |
Related errors we fix
Stop Google OAuth redirect_uri_mismatch recurring in AI-built apps
- →Derive redirect_uri from window.location.origin or NEXTAUTH_URL — never hard-code.
- →Add a CI step that diffs GOOGLE_CLIENT_ID against the env var in Vercel production.
- →Document every Authorized redirect URI in the repo so new environments get allowlisted on day one.
- →Pick a canonical host (apex or www) and redirect the other so you only maintain one URI set.
- →On every release, run a scripted incognito sign-in against production and fail the deploy on 400.
Still stuck with Google OAuth redirect_uri_mismatch?
Fix Google sign-in in under an hour — or we make it our problem.
- →We confirm client_id parity, Authorized URIs, and middleware rewrites
- →Works even when your Google Cloud project was auto-provisioned by a builder
- →Written 1-page report so you understand the fix, not just ship it
Google OAuth redirect_uri_mismatch questions
What causes Error 400: redirect_uri_mismatch on Google OAuth?+
Where exactly do I add redirect URIs in Google Cloud Console?+
Does Google treat http and https as the same redirect URI?+
Why does my fix work for one environment but fail for another?+
Does changing Authorized JavaScript origins fix redirect_uri_mismatch?+
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.
Hyder Shah leads Afterbuild Labs, shipping production rescues for apps built in Lovable, Bolt.new, Cursor, Replit, v0, and Base44. our rescue methodology.
Google OAuth redirect_uri_mismatch experts
If this problem keeps coming back, you probably need ongoing expertise in the underlying stack.