The OAuth Trap
Why "Sign in with Google" works locally but explodes in production. The 5-part setup that trips up every vibe coder.
The Dreaded Error
Error 400: redirect_uri_mismatch
The redirect URI in the request does not match the ones authorized for the OAuth client.
You followed the tutorial. You copied the keys. You deployed to Vercel. And then... this. Every vibe coder hits this wall. Here's why, and how to fix it forever.
The 5 Places You Must Configure
OAuth isn't just "get a key and go." It's a handshake between 5 different places. Miss any one, and the whole thing fails.
1. Google Console
Create OAuth app
2. Credentials
ID + Secret
3. .env.local
Local secrets
4. Vercel Env
Production secrets
5. Callback URLs
The trap!
Create OAuth App in Google Cloud Console
Go to the Google Cloud Console and create a new project (or use an existing one).
Open Google Cloud Console1. Click + CREATE CREDENTIALS → OAuth client ID
2. If prompted, configure the OAuth consent screen first (External, add your email)
3. Application type: Web application
4. Give it a name (e.g., "My App - Production")
Get Your Client ID and Secret
After creating the OAuth client, Google shows you two values:
123456789-abc123.apps.googleusercontent.comGOCSPX-xxxxxxxxxxxxxxxxxSave These Now
Copy these immediately. You can view the Client ID later, but the Secret is only shown once (you can regenerate it though).
Add to Your Local .env.local
In your project root, create or update .env.local:
# Google OAuth
AUTH_GOOGLE_ID=123456789-abc123.apps.googleusercontent.com
AUTH_GOOGLE_SECRET=GOCSPX-xxxxxxxxxxxxxxxxx
# NextAuth Secret (generate with: npx auth secret)
AUTH_SECRET=your-random-secret-here
# Database
DATABASE_URL=your-database-urlGenerate AUTH_SECRET: Run npx auth secret in your terminal to generate a secure random string.
Add the Same Variables to Vercel
Your local .env.local doesn't exist in production. Vercel needs its own copy.
1. Go to your project in Vercel
2. Click Settings → Environment Variables
3. Add each variable:
| Name | Value |
|---|---|
| AUTH_GOOGLE_ID | 123456789-abc... |
| AUTH_GOOGLE_SECRET | GOCSPX-xxx... |
| AUTH_SECRET | your-secret... |
| DATABASE_URL | postgresql://... |
After Adding Variables
You must redeploy for the new environment variables to take effect. Push a new commit or trigger a manual redeploy.
Configure Callback URLs (THE TRAP!)
This is where 90% of vibe coders get stuck.
Google needs to know which URLs are allowed to receive the login callback. You need BOTH your local AND production URLs.
Go back to Google Cloud Console → Your OAuth Client → Authorized redirect URIs
Add these redirect URIs:
http://localhost:3000/api/auth/callback/googlehttp://localhost:3001/api/auth/callback/googlehttps://yourdomain.com/api/auth/callback/googlehttps://your-app-name.vercel.app/api/auth/callback/googleThe Pattern
[your-domain]/api/auth/callback/google
For NextAuth.js, the callback URL is always /api/auth/callback/[provider]
How OAuth Actually Works
User clicks "Sign in with Google"
Your app → Google
Google asks "Allow this app?"
User approves
Google redirects to callback URL
With auth code
Your app exchanges code for user data
User is logged in!
The trap happens at step 3. If the callback URL isn't in Google's allowed list, it rejects the request with redirect_uri_mismatch.
OAuth Setup Checklist
Still Not Working?
Error: redirect_uri_mismatch
The callback URL doesn't match exactly.
Fix: Check for trailing slashes, http vs https, and port numbers. localhost:3000 is not the same as localhost:3001.
Error: Server configuration problem
Usually means environment variables aren't set in Vercel.
Fix: Go to Vercel → Settings → Environment Variables. Make sure all AUTH_* variables are set. Then redeploy.
Works locally, fails in production
Missing production callback URL in Google Console.
Fix: Add https://yourdomain.com/api/auth/callback/google to Google's authorized redirect URIs.
OAuth consent screen errors
Google is being protective because your app isn't verified.
Fix: For testing, use the same Google account that owns the Cloud project. For production, submit for verification or stay in "Testing" mode with limited users.
Pro Tips
- Add callback URLs proactively. Every time you spin up on a new port or domain, add it to Google before you try to log in.
- Keep a checklist. OAuth setup involves 5 places. Use the checklist above every time you set up a new project.
- Test production separately. Login working locally doesn't mean it works in production. Always test the deployed version.
- Use preview deployments. Vercel generates unique URLs for each PR. Add your main Vercel URL to catch these.
Related Resources
OAuth Providers Guide
Google, GitHub, Apple, X, Facebook, and more - pros, cons, costs, and setup.
View GuideAuthentication Playbook
Compare auth providers: Clerk, NextAuth, Supabase Auth, and more.
Read PlaybookVercel Playbook
Environment variables, deployment, and production setup.
Read PlaybookOAuth in Terminology
Quick definition and analogy for OAuth.
View Term.env.local in Terminology
Why local env files don't exist in production.
View Term