All guides

LEARN \u00b7 DEBUGGING GUIDE

Redirect URL wrong in production: how to debug redirect bugs

A user logs in. Instead of going to the dashboard, they land on `http://localhost:3000` or a staging URL. The redirect is pointing to a development URL that was never updated for production.

BeginnerEnvironment/config debugging

What this usually means

Redirect URLs are often built from the current request's host header, a configured base URL, or a hardcoded string. If the base URL is hardcoded, it only works in one environment. If it is derived from the request, a misconfigured proxy or load balancer can pass the wrong host header. OAuth flows are especially vulnerable because the redirect URL must exactly match what is registered with the OAuth provider.

( 01 )Fast diagnosis

The first ten minutes \u2014 establish facts before touching code.

  • 1Find the redirect URL construction code. Is it hardcoded? Is it reading an env var? Is it derived from the request?
  • 2Check the `BASE_URL` or `SITE_URL` environment variable in production. Is it set correctly?
  • 3Check if the app is behind a proxy or load balancer. The `Host` header might be the internal service name, not the public domain.
  • 4Check OAuth provider settings. The registered redirect URL must match exactly the URL the app generates.
  • 5Check if the redirect uses `window.location.origin` on the frontend. If the frontend is served from a different domain, this picks up the wrong origin.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • searchEnvironment variable for base URL — `BASE_URL`, `SITE_URL`, `NEXT_PUBLIC_SITE_URL`
  • searchRedirect construction code — server-side redirects in auth handlers, middleware, or controllers
  • searchOAuth provider dashboard — registered redirect URIs
  • searchProxy/CDN config — X-Forwarded-Host, X-Forwarded-Proto headers
  • searchFrontend code — any client-side redirects using `window.location` or `router.push()`
  • searchServer framework's trust proxy setting — Express `app.set('trust proxy', true)`, Next.js `trustHost`
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningHardcoded redirect URL pointing to localhost or a development domain
  • warning`BASE_URL` environment variable is not set in production — falls back to a development default
  • warningProxy/CDN passes internal hostname as the `Host` header instead of the public domain
  • warning`X-Forwarded-Proto` header is not set or not trusted — redirect URL uses `http` instead of `https`
  • warningOAuth redirect URI registered with the provider does not match the generated URL exactly (trailing slash, www prefix)
  • warningFrontend builds the redirect URL from `window.location` which picks up the wrong origin in an iframe or SSR context
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildSet `BASE_URL` environment variable explicitly in every environment — never rely on request headers alone
  • buildConfigure your server framework to trust proxy headers: Express `app.set('trust proxy', 1)`, Next.js `trustHost: true`
  • buildUse a redirect builder function that constructs URLs from the configured base URL, not from the request
  • buildRegister multiple redirect URIs with OAuth providers — one for each environment plus a trailing-slash variant
  • buildAdd a smoke test that follows a redirect chain and asserts the final URL is correct
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedDeploy to staging. Log in and verify the redirect lands on the staging dashboard, not localhost.
  • verifiedUse curl to follow the redirect: `curl -v -L https://example.com/login/callback?code=...` and check the Location headers.
  • verifiedTest with and without a trailing slash in the OAuth redirect URI.
  • verifiedTest HTTP to HTTPS redirect: accessing the HTTP version should redirect to HTTPS without losing the path.
  • verifiedDeploy to production and run the same verification.
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningHardcoding any URL that includes a domain name
  • warningNot setting the BASE_URL in every environment explicitly
  • warningNot testing OAuth redirect flows in staging before production deploy
  • warningAssuming the request's Host header is always the public domain
  • warningForgetting to register the production redirect URI with the OAuth provider