To secure Redis sessions, you need to: (1) use TLS connections to Redis in production, (2) regenerate session IDs after login to prevent session fixation attacks, (3) set cookies as httpOnly and secure with proper sameSite settings, (4) configure appropriate session TTLs, and (5) use a strong session secret (32+ characters). This blueprint ensures session management follows security best practices for server-side storage.
TL;DR
Redis sessions are faster than database sessions but require secure configuration. Use TLS connections, generate cryptographically secure session IDs, implement session rotation on authentication state changes, and set proper TTLs to limit session lifetime.
Express Session with Redis Redis
import session from 'express-session'
import RedisStore from 'connect-redis'
import { createClient } from 'redis'
// Secure Redis connection
const redisClient = createClient({
url: process.env.REDIS_URL,
socket: {
tls: process.env.NODE_ENV === 'production',
rejectUnauthorized: true,
},
})
await redisClient.connect()
export const sessionMiddleware = session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET!, // 32+ characters
name: 'sessionId', // Don't use default 'connect.sid'
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
sameSite: 'lax',
maxAge: 1000 * 60 * 60 * 24, // 24 hours
},
})
Session Rotation
import { Request, Response, NextFunction } from 'express'
export async function login(req: Request, res: Response) {
// Verify credentials...
const user = await verifyCredentials(req.body)
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' })
}
// CRITICAL: Regenerate session ID after login
// Prevents session fixation attacks
req.session.regenerate((err) => {
if (err) {
return res.status(500).json({ error: 'Session error' })
}
req.session.userId = user.id
req.session.loginTime = Date.now()
res.json({ success: true })
})
}
export async function logout(req: Request, res: Response) {
req.session.destroy((err) => {
if (err) {
return res.status(500).json({ error: 'Logout failed' })
}
res.clearCookie('sessionId')
res.json({ success: true })
})
}
Session Validation Middleware
export function requireAuth(req: Request, res: Response, next: NextFunction) {
if (!req.session.userId) {
return res.status(401).json({ error: 'Not authenticated' })
}
// Optional: Check session age for sensitive operations
const sessionAge = Date.now() - (req.session.loginTime || 0)
const maxAge = 1000 * 60 * 30 // 30 minutes for sensitive ops
if (req.path.includes('/sensitive') && sessionAge > maxAge) {
return res.status(401).json({ error: 'Please re-authenticate' })
}
next()
}
// For very sensitive operations, require re-authentication
export function requireRecentAuth(maxAgeMs = 1000 * 60 * 5) {
return (req: Request, res: Response, next: NextFunction) => {
const sessionAge = Date.now() - (req.session.loginTime || 0)
if (sessionAge > maxAgeMs) {
return res.status(401).json({
error: 'Please re-authenticate for this operation',
requireReauth: true,
})
}
next()
}
}
Always regenerate session ID after login. Session fixation attacks trick users into authenticating with attacker-controlled session IDs. Regenerating prevents this.
Security Checklist
Pre-Launch Checklist
Redis connection uses TLS
Session ID regenerated on login
Cookies are httpOnly and secure
Session TTL configured
Session secret is strong (32+ chars)
Related Integration Stacks
NextAuth + Prisma Database Sessions Clerk Managed Sessions OAuth Token Management