Secure Session Management with Redis
Express sessions with Redis store, expiration, and fingerprinting
What You’ll Build
After following this guide, you will have a working implementation of secure session management with redis in your project. Replace in-memory Express sessions with Redis-backed sessions for production. Includes secure cookie configuration, session expiration, browser fingerprinting to prevent session hijacking, and automatic cleanup of expired sessions.
Use Cases & Problems Solved
- Protect routes so only authenticated users can access sensitive pages
- Allow users to sign up, log in, and manage their accounts securely
- Avoid storing raw passwords or building session management from scratch
Prerequisites
- Redis server running (local or cloud)
- Express.js project
- Node.js 18+
Step-by-Step Implementation
Install dependencies
The following snippet shows how to install dependencies. Copy this into your project and adjust the values for your environment.
npm install express-session connect-redis ioredis
Configure Redis session store
The following snippet shows how to configure redis session store. Copy this into your project and adjust the values for your environment.
const session = require('express-session');
const RedisStore = require('connect-redis').default;
const Redis = require('ioredis');
const redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379');
app.use(session({
store: new RedisStore({ client: redis }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
sameSite: 'strict',
maxAge: 24 * 60 * 60 * 1000, // 24 hours
},
}));
Session usage in routes
The following snippet shows how to session usage in routes. Copy this into your project and adjust the values for your environment.
// Set session data after login
app.post('/login', async (req, res) => {
const user = await authenticateUser(req.body);
req.session.userId = user.id;
req.session.userAgent = req.headers['user-agent']; // fingerprint
res.json({ message: 'Logged in' });
});
// Check session with fingerprint validation
app.get('/profile', (req, res) => {
if (!req.session.userId) return res.status(401).json({ error: 'Not logged in' });
if (req.session.userAgent !== req.headers['user-agent']) {
req.session.destroy(); // possible hijacking
return res.status(401).json({ error: 'Session invalid' });
}
res.json({ userId: req.session.userId });
});
// Logout
app.post('/logout', (req, res) => {
req.session.destroy(() => res.clearCookie('connect.sid').json({ message: 'Logged out' }));
});
⚠️ Don’t Do This
❌ Using default MemoryStore in production
// MemoryStore leaks memory, doesn't scale, loses sessions on restart!
app.use(session({
secret: 'keyboard cat',
resave: true, // Also bad!
saveUninitialized: true, // Creates empty sessions
}));
✅ Always use Redis/DB-backed store in production
app.use(session({
store: new RedisStore({ client: redis }),
secret: process.env.SESSION_SECRET, // from env var
resave: false,
saveUninitialized: false,
}));
Testing
Add these tests to verify your secure session management with redis implementation works correctly:
// __tests__/redis.test.ts
import { describe, it, expect } from 'vitest';
describe('Secure Session Management with Redis', () => {
it('should handle successful authentication', async () => {
// Test the happy path
const result = await authenticate({ email: 'test@example.com', password: 'valid' });
expect(result.user).toBeDefined();
expect(result.error).toBeNull();
});
it('should reject invalid credentials', async () => {
const result = await authenticate({ email: 'test@example.com', password: 'wrong' });
expect(result.user).toBeNull();
expect(result.error).toBeDefined();
});
it('should handle missing fields', async () => {
const result = await authenticate({ email: '', password: '' });
expect(result.error).toBeDefined();
});
});
Verification
# Start Redis
redis-server
# Start your app
npm start
# Login and check Redis for the session key
redis-cli KEYS 'sess:*'
# Should show your session key with TTL Related Specs
Role-Based Access Control (RBAC)
Role/permission system with middleware, database schema, and route guards
JWT Authentication in Express.js
Access/refresh token pattern with middleware guards and secure cookie storage