DEV Community

Barkamol Valiev
Barkamol Valiev

Posted on

Managing JWT Logout with Blacklists and Redis: A Beginner-Friendly Guide

When building secure APIs with JWT (JSON Web Tokens), handling user logout can be tricky. Since JWT is stateless, there’s no out-of-the-box way to invalidate tokens after logout. That’s where blacklists and tools like Redis come into play. If you’re new to these concepts, don’t worry! This guide will explain everything step by step and help you implement a practical solution.

Understanding Statelessness and JWT

Stateless Systems

  • Stateless systems don’t store any user session information on the server.
  • Each request carries all the necessary data (e.g., a JWT) for the server to process it.

JWT

  • JWT contains user data (like id and role) and is signed by the server.
  • Once issued, the server doesn’t need to store the token or session details.
  • Problem: If a user logs out, their JWT remains valid until it expires.

What is a Blacklist?

A blacklist is a list of tokens that have been invalidated. When a user logs out, their token is added to this list. Every time a request is made, the server checks if the token is in the blacklist. If it is, the request is rejected.

Steps to Implement a Blacklist:

  1. Store invalidated tokens in a data structure (e.g., an array, Set, or database).
  2. When processing requests, verify the token is not in the blacklist.
  3. Add a cleanup mechanism to remove expired tokens from the blacklist.

Why Redis?

Redis is a high-performance, in-memory key-value database. It’s perfect for use cases like blacklisting JWTs because:

  • Speed: Redis can handle thousands of read/write operations per second.
  • Distributed: Multiple servers can share the same Redis instance for consistent data.
  • TTL (Time-to-Live): Redis can automatically remove entries after a specified duration.

How to Start Without Redis

If you’re new to these concepts, start with a simple in-memory solution:

const blacklist = new Set();

// Add token to blacklist
authController.logout = (req, res) => {
  const token = req.headers.authorization.split(" ")[1];
  blacklist.add(token);
  res.status(200).json({ message: "Logged out successfully" });
};

// Middleware to check token validity
middleware.verifyToken = (req, res, next) => {
  const token = req.headers.authorization.split(" ")[1];
  if (blacklist.has(token)) {
    return res.status(401).json({ message: "Invalid token" });
  }
  next();
};
Enter fullscreen mode Exit fullscreen mode

This approach works for small-scale projects but has limitations. If your app scales, you’ll need a more robust solution like Redis.

Getting Started with Redis

1. Install Redis

  • Install Redis locally: Redis Installation Guide
  • Alternatively, use a cloud service like AWS Elasticache or Redis Cloud.

2. Integrate Redis in Node.js

Use the ioredis library to interact with Redis in your Node.js app:

npm install ioredis
Enter fullscreen mode Exit fullscreen mode
const Redis = require("ioredis");
const redis = new Redis();

// Add token to Redis with TTL
const logout = async (req, res) => {
  const token = req.headers.authorization.split(" ")[1];
  const expiresIn = 3600; // 1 hour
  await redis.setex(token, expiresIn, "blacklisted");
  res.status(200).json({ message: "Logged out successfully" });
};

// Middleware to check Redis blacklist
const verifyToken = async (req, res, next) => {
  const token = req.headers.authorization.split(" ")[1];
  const isBlacklisted = await redis.get(token);
  if (isBlacklisted) {
    return res.status(401).json({ message: "Invalid token" });
  }
  next();
};
Enter fullscreen mode Exit fullscreen mode

Redis vs In-Memory

Feature In-Memory (Set) Redis
Scalability Limited to a single server Distributed across servers
Speed Very fast Equally fast
Persistence Lost on server restart Data persists across restarts
Cleanup Manual Automatic with TTL

Next Steps

  • Learn Redis Basics: Understand commands like SETEX, GET, and DEL.
  • Secure Redis: Use authentication and IP whitelisting.
  • Optimize Blacklist: Store only token hashes for added security.

Starting simple with an in-memory solution and gradually transitioning to Redis ensures you don’t get overwhelmed. Happy coding!


Let me know in the comments if you have any questions or need help with Redis setup. 🚀

Top comments (0)