Security Engineering

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.

Khalid Aboubakr
15 min read
Session ManagementCookiesCsrfSession FixationSecurityToken RotationHttponly

Introduction

Session management is the foundation of user authentication. Poor session handling leads to account takeover, data breaches, and compliance violations.

// 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:

  1. Secure cookie flags - httpOnly, secure, sameSite
  2. CSRF protection - tokens or double-submit cookies
  3. Session regeneration - on login and privilege changes
  4. Timeout policies - both idle and absolute
  5. Proper logout - invalidate everywhere

Remember: sessions are the keys to your users' accounts. Protect them accordingly.

Related Articles

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.

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.