Secure Session Management: Patterns and Pitfalls
Implement secure session management with proper cookie settings, token rotation, and logout flows. Covers session fixation, hijacking prevention, and multi-device handling.
Introduction
Session management is the foundation of user authentication. Poor session handling leads to account takeover, data breaches, and compliance violations.
Secure Cookie Configuration
// Secure session cookie configuration const sessionCookieOptions: CookieOptions = { httpOnly: true, // Prevents JavaScript access (XSS protection) secure: true, // HTTPS only sameSite: 'strict', // CSRF protection maxAge: 24 * 60 * 60 * 1000, // 24 hours path: '/', domain: process.env.COOKIE_DOMAIN, }; // Set session cookie res.cookie('sessionId', sessionId, sessionCookieOptions); // For cross-site scenarios (OAuth, embedded widgets) const crossSiteCookieOptions: CookieOptions = { ...sessionCookieOptions, sameSite: 'none', // Required for cross-site secure: true, // Mandatory with sameSite: 'none' };
CSRF Protection
import csrf from 'csurf'; // Synchronizer Token Pattern const csrfProtection = csrf({ cookie: { httpOnly: true, secure: true, sameSite: 'strict', }, }); app.use(csrfProtection); // Include token in forms app.get('/form', (req, res) => { res.render('form', { csrfToken: req.csrfToken() }); }); // For SPAs: Double Submit Cookie Pattern app.use((req, res, next) => { if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(req.method)) { const cookieToken = req.cookies['csrf-token']; const headerToken = req.headers['x-csrf-token']; if (!cookieToken || cookieToken !== headerToken) { return res.status(403).json({ error: 'CSRF validation failed' }); } } next(); });
Session Fixation Prevention
class SessionService { async regenerateSession(req: Request): Promise<string> { const oldSessionId = req.cookies.sessionId; const newSessionId = crypto.randomUUID(); if (oldSessionId) { // Copy session data to new session const sessionData = await this.sessionStore.get(oldSessionId); if (sessionData) { await this.sessionStore.set(newSessionId, sessionData); } // Delete old session await this.sessionStore.delete(oldSessionId); } return newSessionId; } async login(req: Request, res: Response, user: User): Promise<void> { // ALWAYS regenerate session on login const newSessionId = await this.regenerateSession(req); await this.sessionStore.set(newSessionId, { userId: user.id, createdAt: new Date(), ipAddress: req.ip, userAgent: req.headers['user-agent'], }); res.cookie('sessionId', newSessionId, sessionCookieOptions); } }
Session Timeout
interface SessionConfig { absoluteTimeout: number; // Maximum session lifetime idleTimeout: number; // Timeout after inactivity renewalThreshold: number; // When to refresh session } class SessionManager { constructor(private config: SessionConfig) {} async validateSession(sessionId: string): Promise<SessionValidationResult> { const session = await this.sessionStore.get(sessionId); if (!session) { return { valid: false, reason: 'SESSION_NOT_FOUND' }; } const now = Date.now(); // Check absolute timeout if (now - session.createdAt > this.config.absoluteTimeout) { await this.sessionStore.delete(sessionId); return { valid: false, reason: 'ABSOLUTE_TIMEOUT' }; } // Check idle timeout if (now - session.lastActivityAt > this.config.idleTimeout) { await this.sessionStore.delete(sessionId); return { valid: false, reason: 'IDLE_TIMEOUT' }; } // Update last activity session.lastActivityAt = now; await this.sessionStore.set(sessionId, session); return { valid: true, session }; } }
Secure Logout
async function logout(req: Request, res: Response): Promise<void> { const sessionId = req.cookies.sessionId; if (sessionId) { // Delete server-side session await sessionStore.delete(sessionId); // Revoke any associated tokens await tokenService.revokeSessionTokens(sessionId); } // Clear all auth-related cookies res.clearCookie('sessionId', { path: '/' }); res.clearCookie('refreshToken', { path: '/api/auth/refresh' }); // Set cache control to prevent back button access res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); res.setHeader('Pragma', 'no-cache'); res.setHeader('Expires', '0'); res.json({ message: 'Logged out successfully' }); }
Conclusion
Secure session management requires:
- Secure cookie flags - httpOnly, secure, sameSite
- CSRF protection - tokens or double-submit cookies
- Session regeneration - on login and privilege changes
- Timeout policies - both idle and absolute
- Proper logout - invalidate everywhere
Remember: sessions are the keys to your users' accounts. Protect them accordingly.
Related Articles
Security Engineering21 min read
Authentication and Authorization in Production Systems
Implement secure JWT authentication with refresh token rotation, RBAC, and OAuth 2.0 flows. Production patterns from healthcare and government systems.
Security Engineering18 min read
API Security Hardening: A Practitioner's Guide
Secure your APIs with rate limiting, input validation, and CORS configuration. Production-tested checklist covering authentication, encryption, and error handling.
Security Engineering16 min read
Protecting Against Injection Attacks: SQL, NoSQL, and XSS
Prevent SQL injection, NoSQL injection, and XSS attacks with validated code patterns. Covers parameterized queries, input sanitization, and CSP configuration.
Payment Integrations28 min read
Stripe Payment Integration: Production Patterns for React and Node.js
Production Stripe integration with Payment Intents, webhooks, and 3D Secure. Covers subscription billing, error handling, and PCI compliance patterns.
Payment Integrations24 min read
HyperPay Payment Integration for Saudi Arabia and GCC
Production-ready HyperPay integration for Saudi and GCC e-commerce. Covers mada card processing, STC Pay, Apple Pay, Copy and Pay forms, and SAMA compliance requirements.