Next.js Curriculum
HardSecurity100% Free35 min read

Session Management: Cookies, Iron Session, and JWTs in App Router

The 30-Second Interview Answer

Session management in App Router relies on secure, HttpOnly, SameSite cookies. Server Components read cookies asynchronously via cookies() to personalize views, while Server Actions and Route Handlers can read and write cookies. Standard architectural patterns include encrypted stateless session cookies (iron-session) or stateful database-backed session tokens.

Learning Objectives

Configure secure cookie attributes: HttpOnly, Secure, SameSite=Lax/Strict, and Path.

Explain the trade-offs between stateless JWT cookies and stateful database session identifiers.

Implement session verification in Server Components using async cookies().

Handle cookie mutation restrictions between Server Components and Server Actions.

Prerequisites & Background Knowledge
HTTP Cookie security flagsJSON Web Tokens (JWT)Session hijacking mitigations

Why Interviewers Care

Every production web application requires secure authentication. Interviewers test your ability to structure auth without security holes.

The Challenge

How does session management operate in Next.js App Router? Implement a secure session reader using async cookies() and explain why Server Components can read cookies but cannot set them.

Code Architecture & Implementation

1// lib/auth/session.ts
2import { cookies } from 'next/headers';
3import { verifyJwt } from '@/lib/auth/jwt';
4
5export interface UserSession {
6 userId: string;
7 email: string;
8 role: 'admin' | 'user';
9}
10
11// Reusable server-side session retrieval
12export async function getSession(): Promise<UserSession | null> {
13 // In Next.js 15+, cookies() is asynchronous!
14 const cookieStore = await cookies();
15 const sessionToken = cookieStore.get('auth_session')?.value;
16
17 if (!sessionToken) return null;
18
19 try {
20 const payload = await verifyJwt(sessionToken);
21 return payload as UserSession;
22 } catch (err) {
23 return null; // Expired or tampered token
24 }
25}

Architectural Explanation

A fundamental constraint of streaming HTTP responses is that response headers (including Set-Cookie) must be emitted before the response body streams. Because Server Components render the response body, calling cookieStore.set() inside a Server Component throws an error. Cookie mutations must take place in Server Actions or Route Handlers. Storing session tokens in HttpOnly; Secure; SameSite=Lax cookies ensures tokens cannot be stolen via Cross-Site Scripting (XSS) or submitted via cross-site forged requests.

Common Mistakes & Anti-Patterns

Attempting to call `cookies().set(...)` inside a Server Component page or layout.

Storing authentication tokens in `localStorage`, exposing user accounts to instant theft via XSS vulnerabilities.

Using unencrypted JWTs containing sensitive personal data (e.g. phone numbers, addresses).

Interview Follow-Up Traps

The interviewer asks: "Why can Server Actions set cookies while Server Components cannot?" Explain that Server Actions are standalone HTTP POST requests that execute before any response is generated, giving them full control over HTTP response headers.

Frequently Asked Questions

Should I use JWTs or database sessions in Next.js?

Database sessions (e.g. with Lucia Auth or NextAuth database adapters) allow immediate server-side revocation. JWTs are stateless but revocation requires token blocklists.

No. HttpOnly cookies are strictly hidden from document.cookie in the browser.

Refresh tokens in Proxy/Middleware or via a dedicated Server Action check on user activity.