# How to Implement JWT Security with Blocklisting in Node.js: A Production-Ready Guide

> Learn to implement JWT security with blocklisting in Node.js. Secure your tokens by maintaining a revocation list with Redis or Memcached for robust production-ready applications.

- Repository: [Yoni Goldberg/nodebestpractices](https://github.com/goldbergyoni/nodebestpractices)
- Tags: how-to-guide
- Published: 2026-02-26

---

**Implement JWT security with blocklisting in Node.js by maintaining a revocation list of compromised tokens using an external store like Redis or Memcached, then verify each request against this list using middleware such as `express-jwt-blacklist` integrated with `express-jwt`.**

JSON Web Tokens (JWTs) provide stateless authentication for Node.js applications, but their immutable nature creates a critical security gap when tokens require immediate invalidation. The *nodebestpractices* repository (goldbergyoni/nodebestpractices) offers a battle-tested pattern for adding revocation capabilities without dismantling the benefits of JWT architecture. According to the guidelines in [`sections/security/expirejwt.md`](https://github.com/goldbergyoni/nodebestpractices/blob/main/sections/security/expirejwt.md), implementing a **blocklist** (also called a revocation list) allows you to invalidate specific tokens on demand while preserving the stateless verification flow for valid tokens.

## The Challenge of Stateless Token Revocation

JWTs are inherently stateless, meaning that once a token is issued, its signature remains valid until it expires. If a token is compromised or a user needs to be logged out immediately, the application cannot "revoke" the token without breaking the stateless model. The recommended solution is to add a revocation layer on top of JWT, even if it implies losing its stateless nature for the specific purpose of security enforcement.

## Architecture of a JWT Blocklist System

A robust blocklist implementation requires three core components working together:

1. **External Storage**: The default in-memory store is unsuitable for multi-process deployments. Production environments require an external store such as **Redis** or **Memcached**.
2. **Middleware Integration**: The blocklist must be consulted on every request through an `isRevoked` callback in your JWT middleware.
3. **Revocation API**: An endpoint or function that adds token identifiers to the blocklist when users log out or security incidents occur.

## Implementing JWT Blocklisting with express-jwt-blacklist

The *nodebestpractices* repository demonstrates this implementation using the `express-jwt-blacklist` module together with `express-jwt`. This approach treats any token present in the blocklist as invalid while allowing valid tokens to proceed through standard stateless verification.

### Configuring the Blocklist Store

Never use the default in-memory store for production deployments. Instead, configure an external storage adapter. The example in [`sections/security/expirejwt.md`](https://github.com/goldbergyoni/nodebestpractices/blob/main/sections/security/expirejwt.md) demonstrates Memcached configuration, though Redis is equally suitable:

```javascript
const jwt = require('express-jwt');
const blacklist = require('express-jwt-blacklist');

// Configure the blocklist store (use external storage for production)
// Here Memcached is demonstrated; replace with Redis as needed
blacklist.configure({
  tokenId: 'jti',          // JWT ID claim used to identify the token uniquely
  strict: true,           // Enforce strict validation checks
  store: {
    type: 'memcached',
    host: '127.0.0.1',
    port: 11211,
    keyPrefix: 'mywebapp:',
    options: {
      timeout: 1000
    }
  }
});

```

### Integrating Blocklist Verification into Middleware

Supply the `isRevoked` callback to `express-jwt` to enable blocklist verification on each request. This allows the middleware to check the external store before processing the token payload:

```javascript
// Attach JWT middleware with revocation check
app.use(jwt({
  secret: 'my-secret',            // Replace with your real secret or public key
  isRevoked: blacklist.isRevoked // Blocklist verification on each request
}));

```

### Revoking Tokens on Logout

When a user logs out or a security incident requires immediate token invalidation, extract the JWT payload (including the `jti` claim) and add it to the blocklist:

```javascript
// Example endpoint to revoke a token (e.g., logout)
app.get('/logout', (req, res) => {
  // The JWT payload (including the `jti` claim) is available as req.user
  blacklist.revoke(req.user);   // Adds the token ID to the blocklist
  res.sendStatus(200);
});

```

## Production Considerations

Because the blocklist is consulted on every request, latency to your external store (Redis/Memcached) directly impacts API response times. Monitor connection pooling and timeout settings carefully.

As noted in the *nodebestpractices* documentation, adding a blocklist "implies losing its stateless nature" for the revocation check. This trade-off is necessary for security-sensitive operations. The [`README.md`](https://github.com/goldbergyoni/nodebestpractices/blob/main/README.md) file links to the security section providing an overview of the "Support blocklisting JWTs" best practice, emphasizing that the revocation layer sits on top of the standard JWT flow rather than replacing it.

## Summary

- **JWTs cannot be natively revoked** due to their stateless design; a **blocklist** provides the necessary revocation capability.
- **External storage is mandatory** for production: use Redis or Memcached instead of in-memory stores to support multi-process deployments.
- **Integration requires two steps**: configure the blocklist store with a unique token identifier (`jti`), then pass `blacklist.isRevoked` to your `express-jwt` middleware.
- **Revocation is explicit**: call `blacklist.revoke(req.user)` during logout or security events to invalidate tokens immediately.
- Implementation examples are available in [`sections/security/expirejwt.md`](https://github.com/goldbergyoni/nodebestpractices/blob/main/sections/security/expirejwt.md) within the goldbergyoni/nodebestpractices repository.

## Frequently Asked Questions

### What is a JWT blocklist and why do I need one?

A JWT blocklist (or revocation list) is a data store containing identifiers of tokens that should no longer be accepted by your application. You need one because standard JWTs remain valid until their expiration time, meaning compromised tokens cannot be invalidated without a separate tracking mechanism.

### Can I use an in-memory store for JWT blocklisting in production?

No. According to the implementation in [`sections/security/expirejwt.md`](https://github.com/goldbergyoni/nodebestpractices/blob/main/sections/security/expirejwt.md), the default in-memory store is unsuitable for multi-process deployments where each Node.js instance would maintain a separate, inconsistent blocklist. Always use a shared external store like Redis or Memcached.

### How does the `jti` claim work in token revocation?

The `jti` (JWT ID) claim provides a unique identifier for each token. When configuring `express-jwt-blacklist`, setting `tokenId: 'jti'` tells the middleware which payload field to use as the blocklist key. This allows specific tokens to be revoked individually without affecting other sessions for the same user.

### Does using a blocklist make my JWT implementation stateful?

Partially. While valid tokens still follow stateless verification, each request requires a network call to the external blocklist store. As the *nodebestpractices* documentation states, this adds "a revocation layer on top of JWT, even if it implies losing its stateless nature," but this trade-off is essential for production security requirements.