BlogHow to Rotate JWT Secrets Without Downtime
·12 min read·JWTSecrets Team

How to Rotate JWT Secrets Without Downtime

Demonstrates zero-downtime rotation using the kid header and multiple active keys.

How to Rotate JWT Secrets Without Downtime

Key rotation is essential security hygiene, but doing it wrong causes authentication outages. Here's how to do it right.

The Problem

A naive rotation (swap old secret for new, restart) immediately invalidates all existing tokens, logging out every active user.

The Solution: Key ID (kid) Header

JWT supports a kid header claim that identifies which key was used to sign the token. By maintaining multiple active keys during a transition window, you achieve zero-downtime rotation.

Step 1: Generate New Key

const newSecret = crypto.randomBytes(32).toString('hex');
const newKeyId = 'key-2025-02';

Step 2: Add to Key Store (Keep Old Key)

const keyStore = {
  'key-2025-01': process.env.JWT_SECRET_OLD, // existing key
  'key-2025-02': process.env.JWT_SECRET_NEW, // new key
};

Step 3: Sign New Tokens with New Key

const token = jwt.sign(payload, keyStore['key-2025-02'], {
  algorithm: 'HS256',
  keyid: 'key-2025-02',
  expiresIn: '15m',
});

Step 4: Verify Using kid Header

function verifyToken(token) {
  const decoded = jwt.decode(token, { complete: true });
  const kid = decoded?.header?.kid;
  const secret = keyStore[kid];

  if (!secret) throw new Error('Unknown key ID');

  return jwt.verify(token, secret, { algorithms: ['HS256'] });
}

Step 5: Retire Old Key After Transition

Wait until all tokens signed with the old key have expired (based on your token TTL), then remove it from the key store and revoke the old secret.

Timeline

Day 0: Add new key, continue signing with old key
Day 1: Switch signing to new key (old key still in verifier)
Day 1 + token TTL: Remove old key from verifier

This approach ensures no active user gets logged out during rotation.