webroad.online
  1. 1Web
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Tooling
  8. 8React
  9. 9State management
  10. 10Next.js
  11. 11Forms
  12. 12Data and backend
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Animations
  16. 16Testing
  17. 17Architecture
Next.js · Lesson 9 of 12

Authentication and sessions

DB sessions vs JWTs, where to keep the token, the DAL and auth libraries.

Updated

What authentication, authorization and a session are

Three different concepts that often get mixed up:

Concept The question Example
Authentication Who are you? logging in with email + password, Google, a magic link
Session How do I recognize you on the next request? a cookie sent automatically with every request
Authorization Are you allowed to do this? only the author can delete their post

How they work together: you authenticate once → the server creates a session and sets a cookie → on every request, the server reads the cookie, finds out who you are and checks whether you're allowed (authorization).

Two kinds of sessions

A session in the database (stateful)

The cookie holds only a random id. The session data (the user, the expiry) lives on the server, in a sessions table or in Redis.

The cookie holds the data itself (userId, expiry), signed (or encrypted) with a secret key on the server. The server checks the signature — without querying the database. The commonly used format: JWT.

Database session Stateless (a JWT in a cookie)
What's in the cookie a random id the data, signed
A DB query on every request yes (or a cache) no
Instant logout / revocation yes — you delete the row hard — the token is valid until it expires
"Log out of all devices" easy hard
Cookie size small bigger
When apps with sensitive data, fine-grained control simple apps, many servers without a shared DB

Where to keep the token — the important rule

Place Verdict
an HttpOnly; Secure; SameSite=Lax cookie ✓ correct — JS can't read it, so neither can an injected script (XSS)
localStorage / sessionStorage ✗ any script on the page can steal it
a variable in memory (an SPA) possible, but it's lost on reload; needs a refresh token in a cookie

Access tokens and refresh tokens

For APIs, two tokens are often used:

Access token Refresh token
Lifetime short (minutes) long (days, weeks)
Used on every request only to get a new access token
If stolen damage limited in time can be revoked on the server

Sessions in Next.js — the pieces

// shared/api/session.ts
import 'server-only'
import { SignJWT, jwtVerify } from 'jose'
import { cookies } from 'next/headers'

const key = new TextEncoder().encode(process.env.SESSION_SECRET)

export async function createSession(userId: string) {
  const expires = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
  const token = await new SignJWT({ userId }).setProtectedHeader({ alg: 'HS256' }).setExpirationTime(expires).sign(key)
  ;(await cookies()).set('session', token, { httpOnly: true, secure: true, sameSite: 'lax', expires, path: '/' })
}

export async function readSession() {
  const token = (await cookies()).get('session')?.value
  if (!token) return null
  try {
    return (await jwtVerify(token, key, { algorithms: ['HS256'] })).payload as { userId: string }
  } catch {
    return null
  }
}

Where you check — the layers

Layer Role Enough on its own?
proxy.ts an optimistic check: "is there a cookie?" → redirect to /login no — just UX, fast
the Data Access Layer (verifySession) really checks the session, once per request (cache()) yes — this is where the security is
every Server Action / Route Handler authentication + authorization on the specific resource mandatory
the UI (hiding buttons) experience only never
// shared/api/dal.ts
import 'server-only'
import { cache } from 'react'
import { redirect } from 'next/navigation'

export const verifySession = cache(async () => {
  const session = await readSession()
  if (!session) redirect('/login')
  return session
})

Layouts don't re-check on every navigation (they're kept). Put the check in the page, in the DAL or in the action — not only in the layout.

Libraries — don't write authentication yourself

Library Kind When
Auth.js (NextAuth) open source, in your app OAuth (Google, GitHub), DB or JWT sessions
Better Auth open source, in your app email/password, OAuth, 2FA, organizations — complete and typed
Clerk, Auth0, WorkOS, Stack Auth a hosted service ready-made UI, enterprise (SSO), no maintenance
iron-session, jose sessions only you already have the login logic, you just need the cookie

Authentication has many security details (password hashing, rate limiting, password resets, CSRF). A mature library is almost always the right choice.

Summary

  • Authentication = who you are; a session = how you're recognized; authorization = what you're allowed to do.
  • A DB session = easy revocation; a JWT in a cookie = no query, hard revocation.
  • The token lives in an HttpOnly cookie; you check in the DAL and in every action, the proxy is only optimistic.

Official sources

Exercises

Was this page helpful?

One tap — no account needed.