DEV Community

Cover image for JWT vs Cookies in Next.js: What Should We Really Use for Authentication?
Anurag Bagri
Anurag Bagri

Posted on

JWT vs Cookies in Next.js: What Should We Really Use for Authentication?

Authentication looks simple on the surface — until we build a real Next.js application with SSR, middleware, and protected routes.

Most developers start with JWT, then run into issues such as:

  • Tokens not being available on first page load
  • Authentication breaking during SSR
  • Security concerns with localStorage
  • Confusion around cookies vs tokens So let’s clear everything properly, from the ground up, specifically in the context of Next.js.

What Is JWT?

JWT (JSON Web Token) is a compact, self-contained token used to transfer claims between parties.

A JWT consists of three parts:

"header.payload.signature"

What it contains

  1. Header → token type and signing algorithm
  2. Payload → user data such as userId, roles, expiry
  3. Signature → ensures integrity and authenticity

Key properties of JWT

  • Stateless (the server does not store sessions)
  • Usually sent via an Authorization header

Commonly stored in:

  • localStorage (unsafe)
  • memory (temporary)
  • cookies (preferred)

JWT itself is not the problem.
The real issue is how and where we store it.

What Are Cookies?

Cookies are browser-managed key–value storage that automatically travel with HTTP requests.

Example format:

"Set-Cookie: auth_token=xyz; HttpOnly; Secure; SameSite=Strict"

Key properties of cookies

  • Automatically sent with every request
  • Available during server-side rendering

Can be configured as:

  • HttpOnly (JavaScript cannot access it)
  • Secure (HTTPS only)
  • SameSite (CSRF protection)

Cookies are not an authentication mechanism.
They are a transport and storage mechanism.

JWT vs Cookies — The Most Important Clarification

JWT and cookies are not competitors.This misunderstanding causes most authentication bugs.JWT defines what proves identityCookies define how that proof is stored and sent.

We can:

  • Store JWT inside cookies (best approach)
  • Send JWT via headers (problematic in Next.js)
  • Store sessions inside cookies

So the real comparison is not JWT vs cookies, but:

JWT in headers vs JWT in cookies

Why JWT Alone Fails in Next.js

Next.js is not just a frontend framework.
It executes code in multiple environments:

  • Server Components
  • Route Handlers
  • Middleware
  • SSR / SSG
  • Client Components

The Core Problem

JWT stored in:

  • localStorage
  • sessionStorage
  • JavaScript memory

is not accessible on the server.This means:

  • The first request has no auth context
  • SSR cannot fetch protected data
  • Middleware cannot validate users
  • Auth-based redirects fail
  • The SSR Problem (The Real Reason Cookies Win)

Consider a user visiting a protected route like /dashboard. With JWT in localStorage the server renders the page. The server has no access to the JWT. The page renders as unauthenticated and client hydrates. JWT is read from storage so the data is refetched.

This causes:

  • UI flickering
  • Security inconsistencies
  • Poor user experience

With Cookies

  • The request reaches the server
  • Cookies are automatically attached
  • The server validates authentication
  • Protected data loads on the first render
  • This single point explains why cookies dominate in Next.js authentication.
  • Extra Capabilities Cookies Provide (Beyond JWT)
  • Cookies unlock platform-level capabilities that JWT alone cannot.

Middleware Authentication

Because cookies are available at the edge, middleware can read them and make routing decisions before a page renders.

Example logic (not code):

"We read the auth cookie in middleware and redirect unauthenticated users before rendering protected routes."

This is impossible with localStorage.

Security by Design

Cookies provide:

  • HttpOnly protection against XSS
  • SameSite protection against CSRF
  • Secure flag for HTTPS-only transmission
  • JWT stored in localStorage provides none of these protections.
  • Works Everywhere in Next.js

Cookies are accessible in:

  • Server Components
  • Route Handlers
  • Middleware
  • API Routes
  • SSR

This creates one unified authentication model across the entire application.

Why Next.js Apps Prefer Cookies (Even When Using JWT)

Most production-grade Next.js apps follow this flow:

"User logs in → Server generates JWT → JWT stored in HttpOnly cookie → Cookie sent automatically → Server validates JWT"

So JWT is still used, but cookies act as the delivery and storage layer.

This approach gives us:

  • Stateless authentication
  • SSR compatibility
  • Strong security guarantees
  • Cleaner architecture

When JWT in Headers Still Makes Sense
JWT sent via headers can still be useful for:

  • Pure backend APIs
  • Mobile applications
  • Third-party integrations
  • Systems without SSR

But for Next.js full-stack applications, cookies are simply the better choice.

Cookies solve:

  • First-request authentication
  • Server-side authorization
  • Middleware protection
  • Major security vulnerabilities

JWT does not disappear —
it just stops being misused.

Top comments (0)