Session Management in Next.js – Stateless Cookies, Database Sessions, Encryption, and Secure Logout

Session management in Next.js ensures that a user's authenticated state persists across requests. This article explains how to create, store, refresh, and delete sessions using stateless cookies or database-backed sessions. It covers JWT encryption with Jose, secure cookie settings, and best practices for performance and security.

Stateless sessionDatabase sessionJWT encryptionCookie management

~4 min read • Updated Oct 26, 2025

Introduction


Session management keeps users logged in across requests. There are two main approaches:

  • Stateless: Session data is stored in browser cookies and verified on the server.
  • Database: Session data is stored in a database, and the browser only receives an encrypted session ID.

For simplicity and security, consider using libraries like iron-session or Jose.


Stateless Sessions with JWT


1. Generate a Secret Key


Use the terminal:

openssl rand -base64 32

Then store it in .env:

SESSION_SECRET=your_secret_key

2. Encrypt and Decrypt Sessions


// app/lib/session.ts
import 'server-only'
import { SignJWT, jwtVerify } from 'jose'

const secretKey = process.env.SESSION_SECRET
const encodedKey = new TextEncoder().encode(secretKey)

export async function encrypt(payload) {
  return new SignJWT(payload)
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('7d')
    .sign(encodedKey)
}

export async function decrypt(session = '') {
  try {
    const { payload } = await jwtVerify(session, encodedKey, {
      algorithms: ['HS256'],
    })
    return payload
  } catch {
    console.log('Failed to verify session')
  }
}

3. Store Session in Cookies


// app/lib/session.ts
import { cookies } from 'next/headers'

export async function createSession(userId) {
  const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
  const session = await encrypt({ userId, expiresAt })
  const cookieStore = await cookies()

  cookieStore.set('session', session, {
    httpOnly: true,
    secure: true,
    expires: expiresAt,
    sameSite: 'lax',
    path: '/',
  })
}

4. Create Session in Server Action


// app/actions/auth.ts
import { createSession } from '@/app/lib/session'

export async function signup(_, formData) {
  // Validate and insert user
  await createSession(user.id)
  redirect('/profile')
}

5. Refresh Session


export async function updateSession() {
  const session = (await cookies()).get('session')?.value
  const payload = await decrypt(session)

  if (!session || !payload) return null

  const expires = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
  const cookieStore = await cookies()
  cookieStore.set('session', session, {
    httpOnly: true,
    secure: true,
    expires,
    sameSite: 'lax',
    path: '/',
  })
}

6. Delete Session


export async function deleteSession() {
  const cookieStore = await cookies()
  cookieStore.delete('session')
}

And in your logout action:

export async function logout() {
  await deleteSession()
  redirect('/login')
}

Database Sessions


To store sessions in a database:

// app/lib/session.ts
import { db } from '@/app/lib/db'
import { encrypt } from '@/app/lib/session'

export async function createSession(id) {
  const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)

  const data = await db.insert(sessions).values({ userId: id, expiresAt }).returning({ id: sessions.id })
  const sessionId = data[0].id
  const session = await encrypt({ sessionId, expiresAt })

  const cookieStore = await cookies()
  cookieStore.set('session', session, {
    httpOnly: true,
    secure: true,
    expires: expiresAt,
    sameSite: 'lax',
    path: '/',
  })
}

Security and Performance Tips


  • Encrypt sessions to prevent tampering
  • Never store sensitive data like passwords or emails in the payload
  • Use database sessions for tracking login history or device management
  • After session setup, implement authorization logic to control access

Conclusion


Session management in Next.js can be implemented using secure cookies or database-backed strategies. With encryption, proper cookie settings, and safe deletion, you can deliver a secure and seamless user experience.


Written & researched by Dr. Shahin Siami