afterbuild/ops
ERR-288/NextAuth · Auth.js
ERR-288
useSession() returns { data: undefined, status: 'unauthenticated' } despite a valid sign-in

appears when:After deploying a Next.js app with NextAuth or Auth.js v5 when useSession returns undefined on production but data and status are correct locally

NextAuth session undefined in production

Auth.js is environment-sensitive. Missing NEXTAUTH_URL, wrong NEXTAUTH_SECRET, or absent SessionProvider all produce the same symptom: the session hook sees nothing.

Last updated 17 April 2026 · 6 min read · By Hyder Shah
Direct answer
NextAuth session undefined in production is almost always a missing env var or missing context provider. Set NEXTAUTH_URL to your production domain, set NEXTAUTH_SECRET to a persistent openssl rand -base64 32 value, and wrap your app in <SessionProvider> inside the root layout.

Quick fix for NextAuth session undefined

app/layout.tsx
typescript
01// app/layout.tsx — wrap the app in SessionProvider (client component)02import { SessionProvider } from "next-auth/react";03import { auth } from "@/auth"; // your NextAuth config04 05export default async function RootLayout({ children }: { children: React.ReactNode }) {06  const session = await auth();07  return (08    <html lang="en">09      <body>10        <SessionProvider session={session}>{children}</SessionProvider>11      </body>12    </html>13  );14}15 16// .env.production — all three must be set on Vercel17// NEXTAUTH_URL=https://myapp.com18// NEXTAUTH_SECRET=<paste openssl rand -base64 32 output>19// AUTH_TRUST_HOST=true  # Auth.js v5 — optional when NEXTAUTH_URL is set20 21// auth.ts — Auth.js v5 canonical config22// import NextAuth from "next-auth";23// import Google from "next-auth/providers/google";24// export const { auth, handlers, signIn, signOut } = NextAuth({25//   providers: [Google],26//   trustHost: true,27// });
Root layout wraps children in SessionProvider with a pre-fetched session, plus the three env vars Auth.js needs in production

Deeper fixes when the quick fix fails

01 · Auth.js v5 — move to the auth() helper in server components

app/dashboard/page.tsx
typescript
01// app/dashboard/page.tsx — server component reads session without useSession02import { auth } from "@/auth";03import { redirect } from "next/navigation";04 05export default async function DashboardPage() {06  const session = await auth();07  if (!session?.user) redirect("/sign-in");08 09  return <div>Welcome, {session.user.email}</div>;10}11 12// auth.ts13import NextAuth from "next-auth";14import Google from "next-auth/providers/google";15 16export const { auth, handlers, signIn, signOut } = NextAuth({17  providers: [Google],18  trustHost: true,19  session: { strategy: "jwt" },20});
Server components avoid SessionProvider altogether — call auth() and read session synchronously

02 · Cookie Secure flag on HTTP preview URLs

If you self-host and serve preview deployments over HTTP, the default __Secure- prefixed cookie never sets because browsers require HTTPS. Disable the prefix in development by setting useSecureCookies: false in your Auth.js config when NODE_ENV !== "production". Do not disable in real production — the Secure flag is a real XSS defense.

auth.ts
typescript
01// auth.ts — opt out of Secure cookies only in dev02export const { auth, handlers } = NextAuth({03  providers: [Google],04  trustHost: true,05  useSecureCookies: process.env.NODE_ENV === "production",06});

03 · Persist secrets correctly in Vercel env

scripts/setup-auth-env.sh
bash
01# 1. generate a secret locally02openssl rand -base64 3203 04# 2. set in Vercel — once, never rotate without a plan05# Dashboard → Settings → Environment Variables → Add06#   NEXTAUTH_URL          https://myapp.com          Production07#   NEXTAUTH_SECRET       <paste the base64 string>  Production, Preview08#   AUTH_TRUST_HOST       true                        Preview09#   GOOGLE_CLIENT_ID      ...                         Production, Preview10#   GOOGLE_CLIENT_SECRET  ...                         Production, Preview11 12# 3. redeploy to pick up the change13vercel deploy --prod
Set once, redeploy, never rotate NEXTAUTH_SECRET without planned user re-sign-in

Why AI-built apps hit NextAuth session undefined

Auth.js (the v5 rebrand of NextAuth) relies on three pieces to rehydrate a session client-side. First, a JWT cookie signed with NEXTAUTH_SECRET. Second, a <SessionProvider> React context that polls the session endpoint. Third, an accurate NEXTAUTH_URL so the provider knows where to call. Break any one and useSession() returns { data: undefined, status: 'unauthenticated' } with no error shown to the user.

AI builders scaffold NextAuth with the quickstart that assumes a local dev setup. They set NEXTAUTH_SECRET in a .env.local that never gets committed, and assume NEXTAUTH_URL defaults to http://localhost:3000. At deploy on Vercel, neither env var exists in the project settings. Auth.js either throws a quiet error in the server log (which the user never sees) or refuses to sign JWTs. The sign-in flow appears to succeed — the provider redirects, the cookie is set — but the JWT has no valid signature or the callback URL points at localhost and the session never rehydrates.

The second pattern is a regenerated secret. Some teams put NEXTAUTH_SECRET in a GitHub Action that rotates on every deploy. Each rotation invalidates every JWT in circulation. Users see themselves logged in for a millisecond, then logged out. The fix is to treat the secret as a fixed production credential managed in Vercel env, not in CI. Rotating it requires planned downtime and user re-sign-in.

The third pattern is missing SessionProvider. The hook throws no error when context is missing — it returns undefined. AI-generated App Router code sometimes forgets to add the provider because it was a Pages Router pattern. Add it to app/layout.tsx wrapped around {children}, pre-fetching the session on the server so the client has data on first paint.

NextAuth session undefined by AI builder

How often each AI builder ships this error and the pattern that produces it.

AI builder × NextAuth session undefined
BuilderFrequencyPattern
LovableEvery NextAuth scaffoldSkips NEXTAUTH_SECRET in Vercel env — dev-only .env.local
Bolt.newCommonPuts SessionProvider inside a client component instead of root layout
v0CommonHardcodes NEXTAUTH_URL=http://localhost:3000 into next.config
CursorSometimesRegenerates NEXTAUTH_SECRET in CI — invalidates every session on every deploy
Replit AgentRareOverrides cookie.domain explicitly — breaks on Vercel preview URLs

Related errors we fix

Stop NextAuth session undefined recurring in AI-built apps

Still stuck with NextAuth session undefined?

Emergency triage · $299 · 48h turnaround
We restore service and write the root-cause report.
start the triage →

NextAuth session undefined questions

Why does useSession return undefined only in production?+
Three likely causes. First, NEXTAUTH_URL is missing or wrong in production env — NextAuth (now Auth.js) needs this to compute callback URLs and cookie origins. Second, NEXTAUTH_SECRET is missing or changed between deployments, which invalidates every signed JWT instantly. Third, the SessionProvider is missing from the app root so the hook has no context to read from. Check all three in order.
Do I need NEXTAUTH_URL if I use AUTH_TRUST_HOST?+
Auth.js v5 accepts AUTH_TRUST_HOST=true as a replacement for NEXTAUTH_URL on platforms like Vercel that set the host header correctly. Use it in preview deployments where the URL is dynamic. For production with a fixed domain still set NEXTAUTH_URL explicitly — it makes debugging simpler and ensures the callback URLs are stable. Never leave both unset.
What goes in NEXTAUTH_SECRET and why does it have to persist?+
NEXTAUTH_SECRET is the HMAC key used to sign session JWTs and CSRF tokens. If it changes, every existing session becomes invalid and every new token fails verification until users sign in again. Generate one with `openssl rand -base64 32` and store it in Vercel project env. Never let the AI regenerate it on each deploy — a different secret means every user's session silently dies.
Why does the session cookie not set on my Vercel preview URL?+
Preview URLs like abc-myapp.vercel.app are subdomains of vercel.app, which is on the public suffix list. Cookies set without an explicit domain work, but cookies set with domain=.myapp.com will not apply. Auth.js defaults to host-only cookies, so previews should work — unless you explicitly configured a cookie domain in the provider config. Remove any cookie.domain override or gate it by NODE_ENV=production.
How long does a NextAuth session fix take?+
Fifteen minutes for env var fixes. Thirty minutes if you need to add SessionProvider to the app root. One hour if the cookie domain is wrong and you need to test across preview, staging, and production. Our Integration Fix service covers the full sweep including a Playwright test that signs in on preview and production to catch regressions per deploy.
Next step

Ship the fix. Keep the fix.

Emergency Triage restores service in 48 hours. Break the Fix Loop rebuilds CI so this error cannot ship again.

About the author

Hyder Shah leads Afterbuild Labs, shipping production rescues for apps built in Lovable, Bolt.new, Cursor, Replit, v0, and Base44. our rescue methodology.

Sources