NextAuth Works Locally but Fails in Production

Hero image for NextAuth Works Locally but Fails in Production. Image by Richard Multimedia.
Hero image for 'NextAuth Works Locally but Fails in Production.' Image by Richard Multimedia.

In Brief

When NextAuth works locally but fails on Vercel, configuration is usually the first place to look. Check the exact failed flow, canonical auth URLs, NEXTAUTH_URL, secrets, cookies, provider callback settings, middleware, HTTPS assumptions, and preview domains before assuming the library behaves differently in production.

Authentication bugs are at their most irritating when they only happen in production.

NextAuth works locally. Signin succeeds. Sessions are readable. Protected routes behave. Then the deployed site loops, drops the session, sends users to the wrong domain, fails callback validation, or behaves differently between preview and production.

That usually means the core auth code is not the first place to look. Production auth failures tend to live in URLs, cookies, secrets, provider configuration, middleware, deployment domains, and environment variables.


Start with the Exact Failed Flow

Do not debug "auth is broken". Debug one flow.

Capture:

  • provider used
  • signin URL
  • callback URL
  • final redirect URL
  • browser console errors
  • network responses
  • cookies set or missing
  • server logs
  • preview or production environment
  • user role or account state

The difference between "callback rejected", "session not persisted", "middleware loop", and "provider refused redirect URI" matters. They can all look like users being sent back to sign in.

If the whole site broke after a release, use a broader production triage checklist first. If only auth is failing, narrow the scope quickly.


Check Canonical Auth URLs

NextAuth configuration depends heavily on the public URL of the app.

Check:

  • NEXTAUTH_URL
  • AUTH_URL if using newer Auth.js naming
  • provider redirect URIs
  • production domain
  • preview domain
  • custom base path
  • trailing slash behaviour
  • HTTP versus HTTPS

The NextAuth documentation says NEXTAUTH_URL should be set to the canonical URL in production, and also documents NEXTAUTH_SECRET. The newer Auth.js deployment docs are useful if the project has moved to the Auth.js naming model.

Relevant references:

The important practical point is this: local callback URLs and production callback URLs are different. OAuth providers usually need the production callback URL registered explicitly. Preview deployments may need their own strategy or may need auth disabled for public review environments.


Verify Secrets and Environment Scope

Missing or inconsistent secrets cause productiononly failures.

Check:

  • secret exists in production
  • secret exists in preview if preview auth is expected
  • secret did not change unintentionally
  • provider client ID and secret match the provider app
  • variables are scoped to the correct Vercel environment
  • variables are not only present in .env.local
  • serveronly variables are not expected in client code

Managing environment variables in Next.js covers the broader pattern. For auth, the risk is sharper because a different secret can invalidate or fail to decode sessions.

Never log secrets to debug this. Log whether expected variable names are present, not their values.


Inspect Cookies in the Browser

Auth bugs often become clear in the cookie panel.

Look for:

  • session cookie set after callback
  • cookie domain
  • Secure flag
  • HttpOnly flag
  • SameSite behaviour
  • cookie path
  • different cookies on preview and production
  • cookies set on the wrong subdomain
  • old cookies surviving across deployments

Local development is forgiving. Production HTTPS, custom domains, preview domains, and crosssite provider redirects are not.

If the callback succeeds but the next request looks unauthenticated, the cookie is a prime suspect. If the cookie is set on one domain and the app expects it on another, the session will appear to vanish.


Check Middleware and Route Protection

Middleware can turn a small auth problem into a loop.

Common mistakes:

  • protecting the auth callback route
  • protecting static assets
  • redirecting already signedin users back to sign in
  • reading a cookie name that changed
  • using different auth config in middleware and API routes
  • failing open locally and failing closed in production
  • matching too many routes

Review route matchers carefully. A middleware rule that looks sensible for /account/:path* may become dangerous if it also catches /api/auth/:path*, preview routes, or provider callbacks.

The older article on using middleware in Next.js for route protection is useful context, but production auth debugging should always inspect the actual deployed matchers.


Check Provider‑Side Settings

OAuth providers are strict, and rightly so.

Check:

  • redirect URI exactly matches production callback
  • provider app is not still in development mode
  • allowed domains include the production domain
  • scopes have not changed
  • client secret has not rotated
  • user test account is permitted
  • callback URL includes base path if the app uses one

The error might not be in your Next.js code. It may be the identity provider rejecting the deployed domain.


Check Session Strategy and Data Availability

If the app uses a databasebacked session, production needs the database and adapter to behave exactly as expected.

Check:

  • database URL
  • migrations
  • adapter configuration
  • network access
  • connection limits
  • user table state
  • account linking data
  • clock skew on token expiry

If the app uses JWT sessions, check secret stability, token size, cookie limits, and callback logic.

Production data can expose cases that local fixtures never covered: old users, duplicate emails, missing profile fields, or accounts linked before a provider changed its payload.


Wrapping Up

When NextAuth works locally but fails in production, the fix is usually not hidden inside a React component.

Start with the failed flow, then check canonical URLs, provider callback settings, secrets, cookie behaviour, middleware, and session storage. Production auth is a contract between your app, the deployment platform, the browser, and the identity provider. Any one of those can be slightly wrong.

The fastest debugging path is to follow the request from signin to callback to cookie to protected route, and stop where the state disappears.

Key Takeaways

  • Debug one auth flow at a time.
  • Check production callback URLs and provider redirect settings first.
  • Verify environment variables and secrets by scope, not only by name.
  • Inspect cookies for domain, Secure, SameSite, and path issues.
  • Make sure middleware does not protect auth callback routes or create loops.
  • Check database or JWT session assumptions with production data.

Have a complex web platform issue?

Tell me what is blocked, what has changed, and what needs to be true after the fix. I'll come back with a practical next step.