NextAuth Session Null in Production: 7 Causes and Fixes

Login works locally but session is null on Vercel? Check NEXTAUTH_URL, secret, trustHost, cookies, callback URLs, and SessionProvider. Exact fixes for NextAuth and Auth.js.

NextAuth (Auth.js) returns a null session in production when the secret or URL is missing or wrong, when the cookie is not being set or sent because of domain or HTTPS settings, or when the OAuth callback URL does not match what the provider has registered.

Work through the causes in this order. They are sorted by how often they cause the problem.

1. Missing or Mismatched Secret

Production requires a secret to sign and encrypt the session. In NextAuth v4 it is NEXTAUTH_SECRET; in Auth.js v5 it is AUTH_SECRET. Without it you get a NO_SECRET error in production or sessions that cannot be decoded.

openssl rand -base64 32

Set the same value in every environment that handles sessions. Using a different secret on two deployments logs users out whenever they hit the other one.

2. Wrong Base URL

NextAuth v4 needs NEXTAUTH_URL set to your canonical production URL, such as https://app.example.com. Setting it to http://localhost:3000 in production is a classic copy-paste mistake and breaks callbacks and cookies. On Vercel, v4 can infer the URL from VERCEL_URL, but a custom domain should be set explicitly.

3. Behind a Proxy: Set trustHost

For Auth.js v5 on self-hosted setups, Docker, or any reverse proxy, the host header may not match what Auth.js expects, producing an UntrustedHost error. Set AUTH_TRUST_HOST=true or trustHost: true in your config, and make sure your proxy forwards X-Forwarded-Host and X-Forwarded-Proto. See also nginx 502 and proxy issues.

On HTTPS, NextAuth uses __Secure- prefixed cookies, which browsers only accept over HTTPS. Check the Network tab: the login response should contain Set-Cookie, and the next request should send it.

Problem Fix
Cookie domain doesn't match Set it to the exact host, or a parent domain for subdomains
sameSite: 'strict' on OAuth return Use lax so the cookie survives the redirect from the provider
TLS ends at the proxy, app thinks HTTP Forward X-Forwarded-Proto: https

A cookie that is dropped also produces redirect loops in middleware.

5. OAuth Callback URL Mismatch

The provider (Google, GitHub) must list the exact callback, for example https://app.example.com/api/auth/callback/google. A staging URL registered but not the production one causes redirect_uri_mismatch or a silent return to the login page.

6. Session Read in the Wrong Place

// Client components need the provider
import { SessionProvider } from 'next-auth/react'

export function Providers({ children }: { children: React.ReactNode }) {
  return <SessionProvider>{children}</SessionProvider>
}

Without SessionProvider, useSession does not behave as expected. On the server, use auth() (v5) or getServerSession(authOptions) (v4) and pass the same options object you used in the route handler. Pass a different config and the session reads as null.

7. Edge Runtime Limits

Middleware runs on the Edge runtime. If your adapter or callbacks use Node-only modules, the session check fails there. Use a split config with an edge-safe auth file for middleware. Related crash patterns are in Vercel Edge Runtime errors.

Quick Production Checklist

  1. AUTH_SECRET / NEXTAUTH_SECRET set in production scope. See env vars undefined.
  2. NEXTAUTH_URL equals the real public URL.
  3. Callback URL registered with the provider.
  4. Cookies visible in DevTools, with the right domain and Secure.
  5. trustHost enabled behind a proxy.
  6. Redeploy after changing any variable.

Let Relia Catch Login Breaks

Auth failures rarely throw: users just land back on the login screen. Relia watches users' sessions, notices when sign-ins start failing, and writes the incident up in plain words: what happened, why it thinks so (with a confidence level), and one thing to do next. On request it writes a fix plan with a "Copy for your AI assistant" button; Relia doesn't change code itself, and after you ship it checks the fix against live traffic.

FAQ

Why is getServerSession null only in production? Usually a missing secret, a wrong NEXTAUTH_URL, or cookies not sent because of domain or HTTPS settings.

What does UntrustedHost mean in Auth.js? Auth.js does not trust the incoming host header. Enable trustHost and forward the correct proxy headers.

Do I need to redeploy after changing NEXTAUTH_URL?

Yes. Environment changes apply only to new deployments.

All guides