Skip to main content

Command Palette

Search for a command to run...

Sessions vs JWT vs Cookies: Understanding Authentication Approaches

Published
6 min read
Sessions vs JWT vs Cookies: Understanding Authentication Approaches

Your application needs to know who's accessing it. When a user logs in, you need to remember they're authenticated so they don't have to log in again for every request. There are three main ways to do this: sessions, cookies, and JWT tokens. Each has different tradeoffs.

What Are Cookies?

Cookies are small pieces of data stored on the client's browser. When you set a cookie, the browser automatically sends it with every request to your server.

Think of cookies like a stamp on your hand at an amusement park. Once you get the stamp, you show it to staff at each ride. The staff don't need to check your ticket every time.

Here's how cookies work:

  1. Server sends a Set-Cookie header in the response

  2. Browser stores the cookie

  3. Browser automatically includes the cookie in every request back to the server

// Setting a cookie in Express
res.cookie('username', 'john', { httpOnly: true, maxAge: 3600000 });
res.send('Cookie set');

Cookies are just a transport mechanism. By themselves, they don't authenticate anyone. They need to work with either sessions or JWT to be useful.

What Are Sessions?

A session is server-side storage of user information. When a user logs in, the server creates a session and stores data about that user. The server then sends a session ID to the client, which stores it in a cookie.

How session-based authentication works:

  1. User logs in with username and password

  2. Server validates credentials and creates a session

  3. Server stores session data (like user ID) in memory or a database

  4. Server sends session ID in a cookie

  5. Browser includes the session cookie in every request

  6. Server looks up the session ID to find user information

This is stateful authentication. The server maintains state about who's logged in.

import express from 'express';
import session from 'express-session';

const app = express();

app.use(session({
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: true,
  cookie: { maxAge: 1000 * 60 * 60 * 24 } // 24 hours
}));

app.post('/login', (req, res) => {
  // Verify user credentials
  const userId = 123;
  
  // Store in session
  req.session.userId = userId;
  res.send('Logged in');
});

app.get('/profile', (req, res) => {
  if (req.session.userId) {
    res.send(`Welcome user ${req.session.userId}`);
  } else {
    res.status(401).send('Not logged in');
  }
});

What is JWT?

JWT stands for JSON Web Token. It's a self-contained token that includes all the information the server needs to authenticate a user. Instead of storing session data on the server, you encode the data into the token itself.

JWT structure:

A JWT has three parts separated by dots: header.payload.signature

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • Header: Specifies the algorithm used to sign the token

  • Payload: Contains claims (data) like user ID and username

  • Signature: Ensures the token hasn't been tampered with

Here's how JWT authentication works:

  1. User logs in with username and password

  2. Server validates credentials

  3. Server creates a JWT with user information

  4. Server sends JWT to the client

  5. Client stores JWT (usually in localStorage or a cookie)

  6. Client sends JWT in the Authorization header with each request

  7. Server verifies the signature and extracts user information

import express from 'express';
import jwt from 'jsonwebtoken';

const app = express();
const SECRET_KEY = 'your-secret-key';

app.post('/login', (req, res) => {
  // Verify user credentials
  const userId = 123;
  const username = 'john';
  
  // Create JWT
  const token = jwt.sign(
    { userId, username },
    SECRET_KEY,
    { expiresIn: '24h' }
  );
  
  res.json({ token });
});

app.get('/profile', (req, res) => {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).send('No token');
  }
  
  try {
    const decoded = jwt.verify(token, SECRET_KEY);
    res.send(`Welcome ${decoded.username}`);
  } catch (error) {
    res.status(401).send('Invalid token');
  }
});

Sessions vs JWT: Key Differences

Aspect Sessions JWT
State Stateful (server keeps data) Stateless (data in token)
Storage Server (memory/database) Client (localStorage/cookie)
Scalability Harder to scale across multiple servers Easy to scale (no server state)
Logout Easy (delete session) Harder (token valid until expiry)
Bandwidth Small cookie sent Larger token sent
Mobile Works with cookies Better for APIs

When to Use Each

Use Sessions When:

  • You're building a traditional web application with server-rendered pages

  • You need immediate logout capability

  • You're running on a single server or have a shared session store

  • You want simpler implementation

Use JWT When:

  • You're building a mobile app or single-page application

  • You have multiple servers that need to authenticate users independently

  • You want a stateless architecture

  • You're building a public API

Use Cookies When:

  • You're setting session IDs or tokens

  • You need automatic browser handling

  • You're building traditional web apps

Common Security Practices

For Sessions:

  • Use secure, HttpOnly cookies

  • Set appropriate session timeout

  • Regenerate session ID on login

  • Use HTTPS only

For JWT:

  • Sign tokens with a strong secret

  • Use HTTPS to prevent token interception

  • Set reasonable expiry times

  • Consider using refresh tokens for longer sessions

  • Keep the secret safe

Real-World Example Comparison

Let's say you have a simple blogging platform. Here's how each approach handles a request flow:

Session-based flow:

  1. User logs in → Server creates session with user ID

  2. User requests profile → Server checks session, recognizes user

  3. User logs out → Server deletes session

JWT-based flow:

  1. User logs in → Server creates token with user ID

  2. User requests profile → Token sent with request, server verifies signature

  3. User logs out → Client simply deletes token

Key Takeaways

  • Cookies are just a transport mechanism, not authentication by themselves

  • Sessions are stateful: server stores user information

  • JWT is stateless: user information is stored in the token itself

  • Sessions are easier for traditional web apps and immediate logout

  • JWT scales better for distributed systems and APIs

  • Both can use cookies for transport; the difference is what data is stored where

Choose the approach based on your application architecture. Traditional web apps often use sessions, while modern APIs and mobile apps commonly use JWT.