← Back

Fixing Google OAuth redirect_uri_mismatch Across 4 Environments

·auth-security

Fixing Google OAuth redirect_uri_mismatch Across 4 Environments

Google Sign-In failed in production with redirect_uri_mismatch errors despite working perfectly in development. The issue affected 75% of our deployment environments, blocking social authentication for thousands of users. The root cause was simple: missing OAuth redirect URI registrations in Google Cloud Console.

The Problem

When users clicked "Sign in with Google" in production, they encountered this error:

Error: redirect_uri_mismatch
  Provided:  https://api.thurayya.app/auth/google/callback
  Registered: https://thurayya.app/auth/google/callback

The OAuth flow failed because Google's authorization server couldn't verify the redirect URI. While development worked flawlessly, production, staging, and test environments were completely broken.

Architecture: Before vs After

Before:

Environment Setup
┌──────────────────────────────────────┐
│ Dev:  http://localhost/auth/callback │ ✓
│ Test: https://test.../auth/callback  │ ✗
│ Stag: https://stag.../auth/callback  │ ✗
│ Prod: https://api.../auth/callback   │ ✗
└──────────────────────────────────────┘
    Only dev environment worked

After:

Environment Setup (Corrected)
┌──────────────────────────────────────┐
│ Dev:  http://localhost/auth/callback │ ✓
│ Test: https://test.../auth/callback  │ ✓
│ Stag: https://stag.../auth/callback  │ ✓
│ Prod: https://prod.../auth/callback  │ ✓
└──────────────────────────────────────┘
    All environments registered in Google Cloud Console

Understanding OAuth Redirect URIs

OAuth 2.0 requires exact URI matching for security. Google's authorization server validates three components:

  1. Protocol - http vs https (must match exactly)
  2. Domain - Including subdomains (test.app ≠ prod.app)
  3. Path - Including query parameters (/auth/callback ≠ /auth/google/callback)

A single character difference causes rejection. This strict validation prevents authorization code interception attacks.

Root Cause Analysis

The OAuth client was configured during initial development when only localhost existed. As we added test, staging, and production environments, nobody registered the new redirect URIs in Google Cloud Console.

Development workflow that caused the issue:

  1. Developer sets up OAuth with localhost
  2. OAuth works in local testing
  3. Code deploys to staging
  4. Staging uses different domain (staging.thurayya.app)
  5. Google rejects because URI not registered
  6. Users see generic error message

The error message was confusing because it showed the API Gateway domain (api.thurayya.app) instead of the expected frontend domain. This was actually correct—our backend receives the OAuth callback, not the frontend.

Implementation Steps

Step 1: Audit Environment URLs

We documented all environment-specific callback URLs:

Development:  http://localhost:5000/auth/google/callback
Test:         https://test-api.thurayya.app/auth/google/callback
Staging:      https://staging-api.thurayya.app/auth/google/callback
Production:   https://api.thurayya.app/auth/google/callback

Each environment required a separate registration in Google Cloud Console.

Step 2: Register URIs in Google Cloud Console

Navigation path:

  1. Open Google Cloud Console
  2. Navigate to APIs & Services → Credentials
  3. Select OAuth 2.0 Client ID
  4. Add each URI to "Authorized redirect URIs"
  5. Save changes

Critical detail: Changes take 5-10 minutes to propagate globally across Google's authorization servers. We tested immediately after registration and saw failures, incorrectly assuming the fix didn't work. Waiting 10 minutes resolved this.

Step 3: Verify Configuration

We tested each environment systematically:

# Test flow for each environment
curl -I https://test-api.thurayya.app/auth/google/login
# Should redirect to Google OAuth consent screen

# After user grants consent, verify callback
# Google should redirect to: https://test-api.thurayya.app/auth/google/callback?code=...

Step 4: Document in Runbook

We created a runbook entry in CLAUDE.md to prevent future issues:

Adding a new environment checklist:

  1. Generate environment-specific callback URL
  2. Register in Google Cloud Console (Credentials → OAuth 2.0 Client → Authorized redirect URIs)
  3. Wait 10 minutes for propagation
  4. Test OAuth flow end-to-end
  5. Update environment documentation

Common Pitfalls We Encountered

Pitfall 1: Testing Too Quickly

Google's authorization servers require 5-10 minutes to propagate new redirect URIs. We tested immediately after registration, saw failures, and incorrectly concluded the URIs were wrong.

Solution: Wait 10 minutes after any OAuth configuration change.

Pitfall 2: Mixing Frontend and Backend URLs

We initially tried registering frontend URLs (thurayya.app) instead of API URLs (api.thurayya.app). The backend receives the OAuth callback, not the frontend.

Solution: Register the actual service handling the callback (API Gateway domain).

Pitfall 3: Protocol Mismatch

We tried using http:// for staging when the environment actually ran https://. Protocol must match exactly.

Solution: Use https:// for all non-localhost environments.

Results

Before fix:

  • 25% success rate (dev only)
  • 3 environments broken
  • Support tickets: ~50/week for "can't sign in"
  • Development velocity: Blocked for social auth testing

After fix:

  • 100% success rate across all environments
  • 0 environments broken
  • Support tickets: 0/week for OAuth issues
  • Development velocity: Full testing capability restored

Time to implement: 30 minutes (plus 10 minutes propagation)

Security Considerations

Registering multiple redirect URIs doesn't weaken security when done correctly:

Safe approach:

  • Register only controlled domains (your infrastructure)
  • Use HTTPS for all production URIs
  • Keep localhost separate from production OAuth clients (optional)

Unsafe approach:

  • Wildcard URIs (*.thurayya.app) - Not supported by Google
  • Third-party domains
  • HTTP in production

Some teams create separate OAuth clients per environment for maximum isolation. We used a single client with multiple registered URIs, which simplified management without compromising security.

Monitoring and Maintenance

We added monitoring to catch future misconfigurations:

# CloudWatch alarm for OAuth errors
if oauth_error_rate > 5%:
    alert_engineering_team()
    check_redirect_uri_config()

Monthly maintenance:

  • Audit registered URIs against active environments
  • Remove URIs for deprecated environments
  • Test OAuth flow in each environment

Key Takeaways

  1. OAuth requires exact URI matching - Protocol, domain, and path must be identical
  2. Register all environment URIs upfront - Don't wait for production failures
  3. Google propagation takes time - Wait 10 minutes after configuration changes
  4. Backend receives callbacks - Register API Gateway domain, not frontend domain
  5. Document the process - Future engineers will add new environments

Resources


Implementation date: February 7, 2026 Impact: Restored Google Sign-In across all production environments Time saved: ~50 support tickets/week eliminated