afterbuild/ops
ERR-400/Google · Supabase · Auth.js
ERR-400
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.

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

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

google-cloud/oauth-client.txt
text
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.
Paste these into Authorized redirect URIs on the matching OAuth 2.0 Client.

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.

app/(auth)/sign-in.tsx
typescript
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.

AI builder × Google OAuth redirect_uri_mismatch
BuilderFrequencyPattern
LovableVery highSupabase OAuth preview URL wired to shared Google client; breaks on first custom domain.
Bolt.newHighHard-codes redirectTo to bolt.new preview host; production URL never allowlisted.
v0HighAuth.js scaffolded with NEXTAUTH_URL unset — callback URL built from edge hostname.
CursorMediumGenerator emits redirectTo without trailing-slash normalization.
ReplitMediumLeftover replit.dev preview URI in Authorized redirect URIs; production apex missing.
Claude CodeLowCorrect dynamic redirect but forgets to document the new Authorized URI per deploy.
WindsurfLowEdits Authorized JavaScript origins instead of Authorized redirect URIs.
Base44MediumProduction 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

Still stuck with Google OAuth redirect_uri_mismatch?

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

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
start the triage →

Google OAuth redirect_uri_mismatch questions

What causes Error 400: redirect_uri_mismatch on Google OAuth?+
Google compares the redirect_uri your app sends with the exact list of Authorized redirect URIs registered for that OAuth client. If the value doesn't match byte-for-byte — including protocol, host, port, path, and trailing slash — Google refuses to redirect back to your app and shows the 400 error. The fix is to copy the URL Google prints in the error screen and paste it into Google Cloud Console → Credentials → your OAuth client → Authorized redirect URIs.
Where exactly do I add redirect URIs in Google Cloud Console?+
Open console.cloud.google.com, select the project used by your app, go to APIs & Services → Credentials, click the OAuth 2.0 Client ID listed under OAuth 2.0 Client IDs (not the Service Account). On that page, 'Authorized redirect URIs' is a list you can append to. Paste the URL, click 'Add URI' if needed, and save. Changes propagate within about a minute.
Does Google treat http and https as the same redirect URI?+
No. Google does an exact-string match on the full redirect_uri, which includes the scheme. http://yourapp.com/auth/callback and https://yourapp.com/auth/callback are two different entries — both must be explicitly listed if you want the app to work on each. For production, use only https and delete any http entries so a misconfigured DNS record cannot fall back to the insecure origin.
Why does my fix work for one environment but fail for another?+
Each environment has a distinct origin — localhost:3000, staging.yourapp.com, yourapp.com — and each origin needs its own entry in the Authorized redirect URIs list. Google supports up to 100 redirect URIs per OAuth client, so add all of them. On the app side, derive the redirect URI from window.location.origin (browser) or NEXTAUTH_URL (server) so the same code works in every environment.
Does changing Authorized JavaScript origins fix redirect_uri_mismatch?+
No. Authorized JavaScript origins controls where Google's sign-in library can be initialized from, not where the server-side redirect can land. The 400 redirect_uri_mismatch error is about the Authorized redirect URIs list, which is a separate field on the same OAuth client page. Updating JavaScript origins without updating redirect URIs will not fix the error.
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.

Google OAuth redirect_uri_mismatch experts

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

Sources