VIBEORIGIN / LEARN
What NextAuth Actually Does
(And Why Your Sessions Keep Breaking)
You added NextAuth to your Next.js app. “Sign in with Google” works. You feel unstoppable. Then you deploy, your session disappears, and you spend 3 hours debugging NEXTAUTH_SECRET. What is this library actually doing under the hood?
What NextAuth Actually Does
NextAuth.js (now called Auth.js) handles three things so you don't read the OAuth 2.0 RFC:
1. Provider Abstraction
Google, GitHub, Discord, email magic links — NextAuth wraps each provider's unique OAuth flow into a single, consistent API. You configure a provider, it handles the redirect dance.
2. Session Management
After login, NextAuth creates a session cookie. Every request to your app includes this cookie. NextAuth decodes it and gives you the user object via getServerSession() or useSession().
3. JWT or Database Sessions
By default, sessions live in an encrypted JWT cookie (no database needed). Add an adapter (Prisma, Drizzle, Supabase) and sessions move to your DB instead.
4. Callback Hooks
signIn, redirect, session, jwt — these callbacks let you control who can sign in, what data goes in the token, and where users land after auth. This is where 90% of customization happens.
In plain English: NextAuth is the glue between OAuth providers and your app's session layer. It doesn't store your users, doesn't build login UIs, and doesn't handle passwords by default. It just manages the handshake and the cookie.
The OAuth Flow, Step by Step
Here's what actually happens when a user clicks “Sign in with Google” in your NextAuth app:
User clicks "Sign in with Google"
|
v
NextAuth redirects to Google's OAuth consent screen
|
v (user approves)
Google redirects back to /api/auth/callback/google
+-- Authorization code in the URL
|
v
NextAuth exchanges code for access token (server-side)
+-- Fetches user profile from Google
+-- Runs signIn() callback (you can block users here)
|
v
Session created:
JWT strategy --> encrypted cookie, no DB needed
DB strategy --> session row in your database + cookie
|
v
User hits a protected route
+-- getServerSession() decodes the cookie
+-- Returns { user: { name, email, image } }
|
v
User is authenticatedThe key insight: your server never sees the user's Google password. Google gives you a token that proves who they are. NextAuth exchanges it and creates a session. That's the entire security model.
Common Misconceptions
"NextAuth handles passwords"
No. NextAuth handles OAuth (Google, GitHub, etc.) and magic links. It has a Credentials provider for passwords, but the docs actively discourage it — you're responsible for hashing, rate limiting, and breach detection. If you want passwords, use a dedicated auth service.
"NextAuth stores my user data"
Only if you configure a database adapter. By default, user info lives entirely in the JWT cookie. No adapter = no database table = no user record anywhere. This is why users 'disappear' when you clear cookies.
"I need NextAuth for protected routes"
NextAuth gives you getServerSession() and middleware, but the actual route protection is just an if-check. You could do this with any JWT library. NextAuth's value is the OAuth plumbing, not the if-statement.
"NextAuth and Auth.js are different things"
Auth.js is the rebrand. NextAuth v5 === Auth.js. Same maintainer, same codebase, but now framework-agnostic (SvelteKit, SolidStart, etc.). If you see 'next-auth' on npm, that's the v4 package. '@auth/core' is v5.
The Thing Nobody Explains: JWT vs Database Strategy
This is the #1 source of NextAuth confusion. When you set up NextAuth, you're making an invisible choice about where sessions live. Most tutorials don't mention this. Then your sessions break and you don't know why.
JWT Strategy (default)
- --Session data lives in an encrypted cookie
- --No database needed — works on Edge, Vercel, Cloudflare
- --Cannot revoke sessions (no server-side record)
- --Cookie size grows as you add data to the token
- --Breaks if NEXTAUTH_SECRET changes (all sessions invalidated)
- --Best for: simple apps, serverless, prototypes
Database Strategy
- --Session ID in cookie, actual data in your DB
- --Requires a database adapter (Prisma, Drizzle, etc.)
- --Can revoke sessions instantly (delete the DB row)
- --Cookie stays small — just a session token
- --Every auth check = 1 DB query (adds latency)
- --Best for: apps needing session control, admin panels, compliance
The rule of thumb: If you don't add a database adapter, you get JWT. If you add one, you get database sessions. You can override this with session: { strategy: "jwt" } — which is useful when you want a database for user records but still want stateless sessions.
When to Use NextAuth vs Alternatives
You want full control over your auth flow, you're comfortable reading docs, and you don't want to pay per-user. Best for developers who want to own their auth layer.
You want a pre-built login UI, user management dashboard, and zero auth code. Trade control for speed. Free tier is generous, but you're locked into their pricing as you scale.
You're already using Supabase for your database. Their auth is built-in, supports OAuth and magic links, and integrates with Row Level Security. Don't add NextAuth on top — use theirs.
You're building an API-only backend with no browser sessions. You issue tokens, clients send them in headers. No cookies, no OAuth dance. Just tokens and middleware.
The Verdict
NextAuth is the best free, open-source auth solution for Next.js if you want to own your auth layer. It's not a managed service — it's a library. You host it, you configure it, you debug it.
If that sounds exhausting, use Clerk. If you're already on Supabase, use their auth. But if you want to understand how authentication actually works — and not pay per-user at scale — NextAuth is the right call.