afterbuild/ops
ERR-401/Supabase · Auth.js · Vercel
ERR-401
Users can't log in after deploy

appears when:first production sign-in after a Vercel deploy — works on localhost, 401 loop on yourapp.com.

Users can't log in after deploy

Login worked locally, fails the moment you ship. Four causes cover nearly every case: rejected session cookie, rotating NEXTAUTH_SECRET, Supabase Site URL stuck on localhost, or CORS blocking the auth endpoint.

Last updated 17 April 2026 · 6 min read · By Hyder Shah
Direct answer

Users can't log in after deploy because production enforces rules localhost ignores: cookies without Secure get dropped over HTTPS, NEXTAUTH_SECRET auto-rotates between Vercel lambdas, and Supabase Site URL still points at localhost. Open devtools → Application → Cookies, sign in, and watch the session cookie. The fix is usually one env var plus aligned cookie options — ships the same day.

Quick fix for users can't log in after deploy

auth.config.ts
typescript
01// Vercel Settings → Environment Variables (Production)02NEXTAUTH_SECRET=$(openssl rand -base64 32)03NEXTAUTH_URL=https://yourapp.com04 05// Supabase Dashboard → Authentication → URL Configuration06Site URL:      https://yourapp.com07Redirect URLs: https://yourapp.com/**08 09// auth.config.ts — align cookie with production10export const config = {11  cookies: {12    sessionToken: {13      name: 'next-auth.session-token',14      options: {15        httpOnly: true,16        sameSite: 'lax',17        secure: true,   // HTTPS only in prod18        path: '/',19      },20    },21  },22};
Paste into auth.config.ts and mirror the env vars in Vercel + Supabase. Redeploy.

Deeper fixes when the quick fix fails

01 · Users can't log in after deploy — fix

The default Supabase client stores sessions in localStorage, which server components cannot read. Every protected route bounces to /login because the server renders signed-out while the browser thinks the user is signed in. Replace the browser client with the @supabase/ssr helpers so the same cookie is readable on both sides.

lib/supabase/server.ts
typescript
01import { createServerClient } from '@supabase/ssr';02import { cookies } from 'next/headers';03 04export async function getSupabase() {05  const store = await cookies();06  return createServerClient(07    process.env.NEXT_PUBLIC_SUPABASE_URL!,08    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,09    {10      cookies: {11        getAll: () => store.getAll(),12        setAll: (all) => all.forEach((c) => store.set(c)),13      },14    },15  );16}
Use cookies, not localStorage, for App Router auth.

02 · Fix CORS on custom auth APIs

If the auth endpoint lives on a different origin (api.yourapp.com) the preflight must return 204 with Access-Control-Allow-Origin and Access-Control-Allow-Credentials: true, and the fetch must include credentials: 'include'. A missing header looks identical to an auth failure in Vercel logs.

app/api/auth/[...path]/route.ts
typescript
01export async function OPTIONS() {02  return new Response(null, {03    status: 204,04    headers: {05      'Access-Control-Allow-Origin': 'https://yourapp.com',06      'Access-Control-Allow-Credentials': 'true',07      'Access-Control-Allow-Methods': 'GET,POST,OPTIONS',08      'Access-Control-Allow-Headers': 'content-type,authorization',09    },10  });11}

03 · Lock the cookie domain for apex + www

If you deploy to both yourapp.com and www.yourapp.com without a canonical redirect, a cookie scoped to one host is invisible on the other. Either force a canonical host in middleware, or set domain: '.yourapp.com' so the session is readable on every subdomain.

Why AI-built apps hit users can't log in after deploy

Lovable, Bolt, and Cursor all scaffold auth with the same optimistic defaults: no Secure cookie flag, no explicit NEXTAUTH_SECRET, Supabase Site URL pointed at whatever preview host the generator was using that week. The generator tests against localhost:3000, sees the login working, and marks the task complete. The whole class of rules that kicks in on HTTPS — browsers refusing SameSite=None without Secure, load balancers rotating lambdas, Safari ITP treating cross-site cookies as tracking — simply never runs in the builder's sandbox.

The most punishing variant is a silent NEXTAUTH_SECRET drift. Auth.js falls back to an auto-generated secret when the env var is unset, and that fallback is stable within a single Vercel lambda instance but changes across cold starts. A user signs in on instance A, gets a token signed with secret A, and on the next request the load balancer routes them to instance B, which has secret B, sees an invalid signature, and logs them out. From the user's point of view, "login works sometimes" — which is worse than outright failure because it looks flaky rather than broken.

Supabase adds its own layer. The default Supabase client stores the session in localStorage, but server components on Next.js 16 App Router only see cookies. If the founder has not wired up the @supabase/ssr helpers, the browser thinks the user is logged in while the server keeps rendering the signed-out state. Every request to a protected route bounces back to /login and the user lands in a redirect loop.

users can't log in after deploy by AI builder

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

AI builder × users can't log in after deploy
BuilderFrequencyPattern
LovableVery highShips Supabase Site URL pointed at preview host; SSR cookie helpers not wired.
Bolt.newHighOmits NEXTAUTH_SECRET from Vercel env; Auth.js falls back to per-instance secret.
v0HighShips Auth.js with default cookie options and no Secure flag for production.
CursorMediumHard-codes cookie domain to www or apex, breaking the other host.
ReplitMediumPreview replit.dev origin leaked into Supabase Site URL and Google OAuth redirects.
Claude CodeLowWrites correct server client but forgets the matching middleware cookie pass-through.
WindsurfLowProduces SameSite=Strict for 'security' — blocks OAuth cross-site redirect.
Base44MediumSession stored in localStorage only; App Router server can't read it.

Related errors we fix

Stop users can't log in after deploy recurring in AI-built apps

Still stuck with users can't log in after deploy?

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

Restore login today — we ship production auth fixes same-day.

  • Diagnosis covers cookies, CORS, Supabase, and NEXTAUTH_SECRET drift
  • Free 30-minute triage before any paid work
  • Written root-cause report you can hand to investors or the team
start the triage →

users can't log in after deploy questions

Why can users log in locally but not after I deploy?+
The gap between localhost and production is almost always one of four things: the auth cookie is set with the wrong domain or a Secure flag that breaks on non-HTTPS, the JWT secret differs between environments, CORS blocks the auth endpoint, or the Supabase Site URL still points at localhost. Each has a distinct signature in the devtools Application → Cookies tab and in server logs — diagnose there first rather than guessing.
What is a NEXTAUTH_SECRET mismatch and how do I detect it?+
The JWT secret (NEXTAUTH_SECRET in Auth.js, JWT_SECRET in custom setups) signs the session token. If the value differs between the instance that issued the token and the one that verifies it, every request returns 401 Unauthorized. You will see 'JWSSignatureVerificationFailed' or 'invalid signature' in Vercel function logs. The fix is to set one consistent value in Vercel Settings → Environment Variables → Production.
How do I fix the login cookie not being set in production?+
In devtools Application → Cookies, sign in and watch the list. If no session cookie appears, the response is stripping the Set-Cookie header — usually because SameSite=None without Secure on HTTP, or a cross-origin API sending cookies without credentials: 'include'. Fix the Secure flag (always true over HTTPS), SameSite (Lax for same-origin, None for cross-origin), and include credentials on the fetch. For Auth.js, NEXTAUTH_URL must match the production origin exactly.
Why does Supabase auth fail after deploy even when env vars are right?+
Supabase Site URL drives the default redirect for email confirmation and password reset links. If it still says localhost, every auth email produces a dead link in production. Additionally, Supabase RLS can block session refresh if auth.uid() returns null due to a misconfigured cookie domain. Confirm Site URL in Supabase Dashboard → Authentication → URL Configuration and check Postgres logs for RLS violations during the login attempt.
How long does it take to fix users can't log in after deploy?+
Usually one to two hours, depending on how many layers need adjustment. The diagnosis takes ten minutes (cookie tab + Vercel logs + Supabase logs). The fix itself is often a single env var or cookie option change. Budget extra time if the auth library is Auth.js with a custom adapter, or if you are juggling multiple deploy environments (staging, production, preview) that each need their own session.
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.

users can't log in after deploy experts

If this problem keeps coming back, you probably need ongoing expertise in the underlying stack.

Sources