jwt-redis-sessions
A secure, production-ready JWT authentication and session management library for Node.js applications using Redis as the session store.
Features
- Secure JWT Implementation - Proper token generation with configurable expiration
- Refresh Token Rotation - Automatic refresh token rotation for enhanced security
- Session Management - Redis-based session storage with automatic cleanup
- Token Revocation - Logout functionality with token blacklisting
- Distributed Rate Limiting - Redis-backed rate limiting across application instances
- TypeScript Support - Full TypeScript definitions included
- Error Handling - Comprehensive error handling with custom error classes
Prerequisites
- Node.js 22 or 24 LTS
- Redis 7.0 or higher
- npm or yarn package manager
Installation
npm install jwt-redis-sessions
# or
yarn add jwt-redis-sessions
Quick Start
1. Start Redis Server
# macOS with Homebrew
brew services start redis
# Ubuntu/Debian
sudo systemctl start redis-server
# Docker
docker run -d -p 6379:6379 redis:7.4.9-alpine
2. Set up environment variables
Set environment variables in the host application (the library does not load .env files):
# Required: Strong JWT secret (minimum 32 characters)
JWT_SECRET=your-super-secure-jwt-secret-key-with-at-least-32-characters-for-production
# Optional: Redis connection (default: redis://localhost:6379)
REDIS_URL=redis://localhost:6379
# Optional: Token expiration times
JWT_ACCESS_TOKEN_EXPIRY=15m
JWT_REFRESH_TOKEN_EXPIRY=7d
Security Note: Generate a cryptographically secure JWT secret:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
3. Basic Usage
const express = require('express')
const {
generateToken,
refreshToken,
revokeToken,
revokeAllUserTokens,
auth,
} = require('jwt-redis-sessions')
const app = express()
app.use(express.json())
// Login endpoint
app.post('/login', async (req, res) => {
try {
// Validate user credentials here
const user = {
userId: 'user123', // Required for revokeAllUserTokens
email: 'user@example.com',
role: 'admin', // Optional additional data
}
// IMPORTANT: For revokeAllUserTokens to work, include at least one of these fields:
// - userId
// - id
// - email
// Generate tokens
const tokens = await generateToken(user)
res.json(tokens)
} catch (error) {
res.status(500).json({ error: error.message })
}
})
// Protected route
app.get('/profile', auth, async (req, res) => {
res.json({
message: 'This is a protected route',
user: req.auth.decoded,
session: req.auth.session,
})
})
// Refresh token endpoint
app.post('/refresh', async (req, res) => {
try {
const refreshTokenValue = req.headers.authorization?.split(' ')[1]
if (!refreshTokenValue) {
return res.status(400).json({ error: 'Refresh token required' })
}
const newTokens = await refreshToken(refreshTokenValue)
res.json(newTokens)
} catch (error) {
res.status(401).json({ error: error.message })
}
})
// Logout current session
app.post('/logout', async (req, res) => {
try {
const token = req.headers.authorization?.split(' ')[1]
if (!token) {
return res.status(400).json({ error: 'Token required' })
}
await revokeToken(token)
res.json({ success: true, message: 'Logged out successfully' })
} catch (error) {
res.status(401).json({ error: error.message })
}
})
// Logout all sessions for the user
app.post('/logout-all', auth, async (req, res) => {
try {
const userIdentifier = req.auth.decoded.userId || req.auth.decoded.id || req.auth.decoded.email
if (!userIdentifier) {
return res.status(400).json({ error: 'User identifier not found in token' })
}
const logoutResult = await revokeAllUserTokens(userIdentifier)
res.json({ success: true, message: logoutResult.message })
} catch (error) {
res.status(401).json({ error: error.message })
}
})
app.listen(3000, () => {
console.log('Server running on http://localhost:3000')
})
Configuration
All configuration is done through environment variables. See .env.example for all available options.
JWT Configuration
JWT_SECRET- Secret key for signing tokens (required, min 32 chars)JWT_ACCESS_TOKEN_EXPIRY- Access token expiration (default: '15m')JWT_REFRESH_TOKEN_EXPIRY- Refresh token expiration (default: '7d')
Redis Configuration
REDIS_URL- Redis connection URL (default: 'redis://localhost:6379')REDIS_HOST- Redis host (default: 'localhost')REDIS_PORT- Redis port (default: 6379)REDIS_PASSWORD- Redis password (optional)SESSION_TTL- Sliding session TTL in seconds (default: 604800)REFRESH_TOKEN_TTL- Refresh-state TTL in seconds (default: 604800)
Payload Configuration
JWT_ALLOWED_TOKEN_FIELDS- Comma-separated allowlist (default:userId,id,email,role,permissions)
Token/session data accepts primitives and arrays of primitives only. Reserved JWT claims and sensitive-looking fields such as passwords, hashes, secrets, and credentials are rejected.
Configuration can also be supplied before the first operation:
const sessions = require('jwt-redis-sessions')
sessions.configure({
jwt: { secret: process.env.JWT_SECRET },
redis: { url: 'rediss://redis.internal:6380' },
})
Configuration becomes immutable after Redis initialization.
API Overview
Token Management
generateToken(data)- Generate access and refresh tokensrefreshToken(token)- Refresh an access tokenrevokeToken(token)- Revoke a specific tokenrevokeAllUserTokens(userIdentifier)- Revoke all tokens for a user
Middleware
auth- Main authentication middlewarerateLimit(maxAttempts, windowMs)- Redis-backed rate limiting middleware
Documentation
- Complete Examples - Full working code examples
- API Reference - Detailed API documentation
- Troubleshooting - Common issues and solutions
- Security Guide - Production security best practices
- Threat Model - Security boundaries and residual risks
- Migration Guide - Required changes from earlier releases
Testing
npm test
npm run test:coverage
npm run test:redis:memory # Real Redis 7.4.9 without Docker
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see LICENSE file for details.
Author
Ahmad Raza
Support
For issues and feature requests, please use the GitHub issue tracker.