Simple session middleware for Express.js applications
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Session cookie configuration and manipulation with security features, expiration handling, and serialization capabilities.
The Cookie class manages session cookie properties and provides serialization methods.
/**
* Session cookie management class
* @param options - Cookie configuration options
*/
class Cookie {
constructor(options?: CookieOptions);
/** Cookie path (default: '/') */
path: string;
/** Max age in milliseconds or null for session cookies */
maxAge: number | null;
/** HttpOnly flag (default: true) */
httpOnly: boolean;
/** Secure flag for HTTPS only */
secure?: boolean;
/** Cookie domain */
domain?: string;
/** SameSite policy */
sameSite?: boolean | 'lax' | 'strict' | 'none';
/** Partitioned attribute for CHIPS */
partitioned?: boolean;
/** Priority level */
priority?: 'low' | 'medium' | 'high';
/** Original maxAge value for resetting */
originalMaxAge?: number;
/**
* Serialize cookie to Set-Cookie header value
* @param name - Cookie name
* @param val - Cookie value
* @returns Serialized cookie string
*/
serialize(name: string, val: string): string;
/**
* Return JSON representation of cookie
* @returns Cookie data object
*/
toJSON(): object;
/** Cookie data object (read-only) */
readonly data: object;
}
interface CookieOptions {
domain?: string;
expires?: Date;
httpOnly?: boolean;
maxAge?: number;
partitioned?: boolean;
path?: string;
priority?: 'low' | 'medium' | 'high';
sameSite?: boolean | 'lax' | 'strict' | 'none';
secure?: boolean | 'auto';
}Usage Examples:
const { Cookie } = require('express-session');
// Create cookie with options
const cookie = new Cookie({
maxAge: 1000 * 60 * 60, // 1 hour
httpOnly: true,
secure: true,
sameSite: 'strict'
});
// Access cookie properties
console.log(cookie.maxAge); // 3600000
console.log(cookie.httpOnly); // true
// Serialize cookie
const cookieString = cookie.serialize('sessionId', 'abc123');
console.log(cookieString); // 'sessionId=abc123; Path=/; HttpOnly; Secure; SameSite=Strict'Cookie expiration can be managed through expires date or maxAge duration.
interface CookieExpiration {
/** Expiration date setter */
set expires(date: Date | undefined);
/** Expiration date getter */
get expires(): Date | undefined;
/** Max age setter (in milliseconds) */
set maxAge(ms: number | Date | null);
/** Max age getter (time remaining in milliseconds) */
get maxAge(): number | null;
}Usage Examples:
// Set expiration using maxAge (recommended)
req.session.cookie.maxAge = 1000 * 60 * 30; // 30 minutes
// Set expiration using specific date
req.session.cookie.expires = new Date(Date.now() + 1000 * 60 * 60); // 1 hour
// Session cookie (expires when browser closes)
req.session.cookie.maxAge = null;
// Check remaining time
app.get('/session-time', (req, res) => {
const remaining = req.session.cookie.maxAge;
if (remaining) {
res.json({
remainingMs: remaining,
remainingMinutes: Math.floor(remaining / 1000 / 60)
});
} else {
res.json({ message: 'Session cookie (no expiration)' });
}
});Security-related cookie properties for protecting session data.
interface CookieSecurity {
/** HttpOnly flag prevents client-side JavaScript access */
httpOnly: boolean;
/** Secure flag requires HTTPS transmission */
secure?: boolean;
/** SameSite policy for CSRF protection */
sameSite?: boolean | 'lax' | 'strict' | 'none';
/** Partitioned attribute for third-party contexts */
partitioned?: boolean;
/** Priority level for cookie retention */
priority?: 'low' | 'medium' | 'high';
}Usage Examples:
// High security configuration
app.use(session({
secret: 'secret',
cookie: {
httpOnly: true, // Prevent XSS
secure: true, // HTTPS only
sameSite: 'strict', // Strong CSRF protection
maxAge: 1000 * 60 * 15 // 15 minutes
}
}));
// Third-party context configuration
app.use(session({
secret: 'secret',
cookie: {
secure: true,
sameSite: 'none', // Allow cross-site
partitioned: true // CHIPS support
}
}));
// Development configuration
app.use(session({
secret: 'secret',
cookie: {
secure: false, // Allow HTTP in development
httpOnly: true,
sameSite: 'lax' // Balanced CSRF protection
}
}));Control cookie scope through domain and path settings.
interface CookieScope {
/** Cookie domain (subdomain control) */
domain?: string;
/** Cookie path (URL path control) */
path: string;
}Usage Examples:
// Subdomain sharing
app.use(session({
secret: 'secret',
cookie: {
domain: '.example.com', // Available to all subdomains
path: '/'
}
}));
// Path-specific sessions
app.use('/admin', session({
secret: 'admin-secret',
name: 'admin.sid',
cookie: {
path: '/admin' // Only available under /admin path
}
}));
// API-specific sessions
app.use('/api', session({
secret: 'api-secret',
name: 'api.sid',
cookie: {
path: '/api',
httpOnly: true,
maxAge: 1000 * 60 * 60 // 1 hour for API sessions
}
}));Methods for converting cookie objects to strings and JSON.
interface CookieSerialization {
/**
* Serialize cookie to Set-Cookie header format
* @param name - Cookie name
* @param val - Cookie value
* @returns Set-Cookie header value
*/
serialize(name: string, val: string): string;
/**
* Convert cookie to JSON representation
* @returns Cookie data object
*/
toJSON(): object;
/** Get cookie data object */
readonly data: object;
}Usage Examples:
// Serialize cookie for custom header manipulation
app.use((req, res, next) => {
if (req.session && req.session.cookie) {
const cookieData = req.session.cookie.toJSON();
console.log('Cookie settings:', cookieData);
// Custom cookie serialization
const customCookie = req.session.cookie.serialize('custom-session', 'value');
res.setHeader('X-Custom-Session', customCookie);
}
next();
});
// Cookie data inspection
app.get('/cookie-info', (req, res) => {
if (req.session) {
res.json({
cookieData: req.session.cookie.data,
cookieJson: req.session.cookie.toJSON(),
maxAge: req.session.cookie.maxAge,
originalMaxAge: req.session.cookie.originalMaxAge
});
} else {
res.json({ error: 'No session found' });
}
});Modify cookie properties during request processing.
interface CookieManipulation {
/** Reset maxAge to original value */
originalMaxAge?: number;
}Usage Examples:
// Extend session for active users
app.use((req, res, next) => {
if (req.session && req.session.lastActivity) {
const timeSinceActivity = Date.now() - req.session.lastActivity;
// Extend session if user was active recently
if (timeSinceActivity < 1000 * 60 * 5) { // 5 minutes
req.session.cookie.maxAge = 1000 * 60 * 30; // Reset to 30 minutes
}
}
next();
});
// Reduce session time for sensitive operations
app.post('/sensitive-operation', (req, res) => {
// Temporarily reduce session timeout
const originalMaxAge = req.session.cookie.maxAge;
req.session.cookie.maxAge = 1000 * 60 * 5; // 5 minutes
performSensitiveOperation().then(() => {
// Restore original timeout
req.session.cookie.maxAge = originalMaxAge;
res.json({ message: 'Operation complete' });
});
});
// Dynamic cookie security based on content
app.use((req, res, next) => {
if (req.path.startsWith('/admin')) {
// Stricter security for admin pages
if (req.session && req.session.cookie) {
req.session.cookie.sameSite = 'strict';
req.session.cookie.secure = true;
}
}
next();
});Access the cookie object through the session.
interface SessionCookieAccess {
/** Cookie object associated with the session */
req.session.cookie: Cookie;
}Usage Examples:
// Cookie property access
app.get('/session-cookie', (req, res) => {
if (req.session) {
res.json({
cookieMaxAge: req.session.cookie.maxAge,
cookiePath: req.session.cookie.path,
cookieSecure: req.session.cookie.secure,
cookieHttpOnly: req.session.cookie.httpOnly,
cookieSameSite: req.session.cookie.sameSite
});
}
});
// Conditional cookie modification
app.use((req, res, next) => {
if (req.session && req.headers['user-agent'].includes('Mobile')) {
// Shorter sessions for mobile devices
req.session.cookie.maxAge = 1000 * 60 * 15; // 15 minutes
}
next();
});