Skip to main content

Command Palette

Search for a command to run...

JWT Authentication vs Sessions — a simple guide (with mini-auth code, diagrams, and banner prompt)

Published
4 min read
JWT Authentication vs Sessions — a simple guide (with mini-auth code, diagrams, and banner prompt)

When building a login system, the biggest question is: “How do I remember that a user is logged in?”

There are two popular ways to do this in Node.js:

  1. Session-based authentication

  2. Token-based authentication (JWTs)

Both work well, but they have different strengths. In this blog, we will explain both approaches, show simple examples, and compare them side by side.


🔑 What is JWT Authentication?

JWT (JSON Web Token) is like a digital ID card.
When a user logs in, the server gives them a signed token (like a stamp of approval).

On every request, the user shows this token to prove who they are.
The server can check the stamp (signature) without needing to look up extra data in a database.

✅ Advantages of JWT

  • No need to store session data on server (stateless).

  • Great for APIs and mobile apps.

  • Easy to scale because no session storage is needed.

⚠️ Disadvantages of JWT

  • Harder to log out users early (you must manage token revocation).

  • If tokens are stolen, they can be misused until they expire.

  • Usually larger than session IDs because they contain encoded data.


🗄️ What is Session Authentication?

Sessions are like lockers.
When a user logs in, the server creates a locker (session) and puts user details inside it.
The server then gives the user a key (session ID, stored in a cookie).

On every request, the user shows the key, and the server opens the locker to check their data.

✅ Advantages of Sessions

  • Easy to log users out (just delete the session).

  • Well-supported by many frameworks.

  • Works well for traditional websites.

⚠️ Disadvantages of Sessions

  • Requires storage (memory, Redis, or database).

  • Can be harder to scale in very large systems.

  • Needs sticky sessions or shared storage across multiple servers.


📊 Comparison: JWT vs Sessions

Here’s a side-by-side comparison to make things clearer:

FeatureJWT AuthenticationSession Authentication
StorageStored on client (usually in localStorage/cookie)Stored on server (DB, Redis, memory)
ScalabilityEasy (stateless, works across servers)Harder (sessions must be shared across servers)
LogoutHarder (must revoke tokens)Easy (destroy session)
SecurityToken theft risk until expirySecure if cookies are HttpOnly + SameSite
Best forAPIs, mobile apps, microservicesTraditional web apps, server-rendered pages

🛠️ Mini Auth System Examples

Let’s see both methods with simple Node.js + Express examples.


1) JWT Authentication Example

// jwt-auth.js
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const cookieParser = require('cookie-parser');

const app = express();
app.use(express.json());
app.use(cookieParser());

const users = []; // fake DB
const JWT_SECRET = 'supersecret';

app.post('/register', async (req, res) => {
  const { email, password } = req.body;
  const hashed = await bcrypt.hash(password, 10);
  users.push({ email, password: hashed });
  res.send('User registered');
});

app.post('/login', async (req, res) => {
  const { email, password } = req.body;
  const user = users.find(u => u.email === email);
  if (!user) return res.status(400).send('Invalid');
  const valid = await bcrypt.compare(password, user.password);
  if (!valid) return res.status(400).send('Invalid');

  const token = jwt.sign({ email }, JWT_SECRET, { expiresIn: '15m' });
  res.json({ token });
});

function authMiddleware(req, res, next) {
  const header = req.headers.authorization;
  if (!header) return res.status(401).send('No token');
  const token = header.split(' ')[1];
  try {
    req.user = jwt.verify(token, JWT_SECRET);
    next();
  } catch {
    res.status(403).send('Invalid token');
  }
}

app.get('/protected', authMiddleware, (req, res) => {
  res.send(`Hello ${req.user.email}`);
});

app.listen(3000, () => console.log('JWT auth running on 3000'));
2) Session Authentication Example
js
Copy code
// session-auth.js
const express = require('express');
const session = require('express-session');
const bcrypt = require('bcrypt');

const app = express();
app.use(express.json());

app.use(session({
  secret: 'supersecret',
  resave: false,
  saveUninitialized: false,
  cookie: { httpOnly: true }
}));

const users = []; // fake DB

app.post('/register', async (req, res) => {
  const { email, password } = req.body;
  const hashed = await bcrypt.hash(password, 10);
  users.push({ email, password: hashed });
  res.send('User registered');
});

app.post('/login', async (req, res) => {
  const { email, password } = req.body;
  const user = users.find(u => u.email === email);
  if (!user) return res.status(400).send('Invalid');
  const valid = await bcrypt.compare(password, user.password);
  if (!valid) return res.status(400).send('Invalid');

  req.session.user = user.email;
  res.send('Logged in');
});

function authMiddleware(req, res, next) {
  if (!req.session.user) return res.status(401).send('Not logged in');
  next();
}

app.get('/protected', authMiddleware, (req, res) => {
  res.send(`Hello ${req.session.user}`);
});

app.listen(3001, () => console.log('Session auth running on 3001'));