Back to skills
SKILL.md
Jwt Token Rotator
ASecurityImplement secure short-lived access token renewal and refresh token rotation with revocation blacklisting.
- 2 stars
- 0 votes
- 0 copies
- 0 views
- Added September 27, 2026
Security analysis
92/100- Installs packages at runtime which could introduce malicious dependencies
npx -y skills add RMAzrim/opencode-artes --skill jwt-token-rotator --agent claude-codeAre you the author of Jwt Token Rotator?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/rmazrim-jwt-token-rotator)---
name: JWT Token Rotator
description: Implement secure short-lived access token renewal and refresh token rotation with revocation blacklisting.
metadata:
source: skills/jwt-token-rotator/jwt-token-rotator.md
---
# JWT Token Rotator
## Prerequisites & Dependencies
- Node.js 18+ with `npm i jsonwebtoken` and `npm i redis` for blacklist storage
- Understanding of OAuth 2.0 / OpenID Connect flow
- Secure secret management: environment variables, HashiCorp Vault, or AWS Secrets Manager
## Execution Steps
1. Issue a short-lived Access Token (e.g., 15min) and a long-lived Refresh Token (e.g., 30 days) upon login
2. Store each issued Refresh Token's `jti` (JWT ID) in Redis with a TTL matching the token lifetime
3. On every protected route request, validate the Access Token; if `expired`, use the Refresh Token to obtain a new Access Token
4. During rotation: delete the old Refresh Token `jti` from Redis (revocation), issue a new Access Token + new Refresh Token pair
5. Reject refresh requests if the `jti` is already blacklisted or missing (single-use refresh)
6. Implement a background cleanup job to prune stale blacklist entries and enforce maximum refresh token age
```javascript
// JWT rotation with Redis blacklist (Node.js/Express)
const jwt = require('jsonwebtoken');
const Redis = require('ioredis');
const redis = new Redis();
const ACCESS_TOKEN_TTL = 15 * 60; // 15 minutes
const REFRESH_TOKEN_TTL = 30 * 24 * 60; // 30 days
// Issue tokens
function issueTokens(userId) {
const access = jwt.sign({ sub: userId, type: 'access' }, process.env.ACCESS_SECRET, { expiresIn: ACCESS_TOKEN_TTL });
const refresh = jwt.sign({ sub: userId, type: 'refresh', jti: crypto.randomUUID() }, process.env.REFRESH_SECRET, { expiresIn: REFRESH_TOKEN_TTL });
// Store refresh jti for revocation
redis.set(refresh.jti, 'revoked', 'EX', REFRESH_TOKEN_TTL);
return { access, refresh };
}
// Refresh endpoint
app.post('/refresh', async (req, res) => {
const { refreshToken } = req.body;
try {
const payload = jwt.verify(refreshToken, process.env.REFRESH_SECRET) as any;
// Check revocation
const isRevoked = await redis.exists(payload.jti);
if (isRevoked) return res.status(401).json({ error: 'Refresh token revoked' });
// Issue new tokens + rotate
const newTokens = issueTokens(payload.sub);
res.json(newTokens);
} catch (err) {
res.status(401).json({ error: 'Invalid refresh token' });
}
});
```
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.