Production-ready rules for building, operating, and securing session management in TypeScript/Node back-ends (Express & NestJS) with Redis, JWT, and HTTPS.
You're tired of cobbling together session management from random tutorials and Stack Overflow answers. You need bulletproof security that scales, handles edge cases gracefully, and doesn't break when your app hits production load. This comprehensive session management ruleset transforms your development workflow from reactive patching to proactive security engineering.
Building session management from scratch creates a massive security debt that compounds over time:
You already know sessions are hard to get right. What you need is a battle-tested approach that eliminates guesswork and implements security-first patterns from day one.
These Cursor Rules implement enterprise-level session management patterns using TypeScript strict mode, Redis clustering, JWT best practices, and comprehensive security hardening. Instead of researching obscure security papers or debugging session fixation attacks at 2 AM, you get proven patterns that handle:
crypto.randomBytes(16) with ≥128 bits entropySecure, HttpOnly, and SameSite cookies automatically// Before: Manual, error-prone session setup
app.use(session({
secret: 'keyboard cat', // ❌ Weak secret
resave: true, // ❌ Unnecessary saves
saveUninitialized: true // ❌ Privacy violation
}));
// After: Production-ready configuration
app.use(session({
name: 'sid',
store: new RedisStore({ client: redis, ttl: 60 * 60 * 8 }),
secret: process.env.SESSION_SECRET, // ✅ Environment-based
resave: false, // ✅ Optimized saves
saveUninitialized: false, // ✅ GDPR compliant
cookie: {
httpOnly: true, // ✅ XSS protection
secure: isProd, // ✅ HTTPS enforcement
sameSite: 'lax', // ✅ CSRF mitigation
maxAge: 900000 // ✅ 15-minute idle timeout
}
}));
SessionData definitions// Typed session data with security metadata
declare module 'express-session' {
interface SessionData {
uid: string;
csrfToken: string;
rotatedAt: number;
meta: {
ip: string;
ua: string;
};
}
}
// Helper functions eliminate boilerplate
export const createSession = async (req: Request, userId: string) => {
req.session.uid = userId;
req.session.csrfToken = crypto.randomBytes(32).toString('hex');
req.session.rotatedAt = Date.now();
req.session.meta = {
ip: req.ip,
ua: req.get('user-agent') || ''
};
};
Express.js Teams Save 8-12 Hours Per Sprint:
NestJS Teams Reduce Auth Complexity by 60%:
SessionSerializer for WebSocket integrationSecurity Teams Approve Faster:
// Concurrent session limits per tenant tier
const SESSION_LIMITS = {
basic: 3,
pro: 10,
enterprise: 50
};
// Automated session cleanup for deleted users
const purgeUserSessions = async (userId: string) => {
const keys = await redis.keys(`sess:*${userId}*`);
if (keys.length > 0) {
await redis.del(...keys);
emitTelemetry('session.bulk_revoked', { userId, count: keys.length });
}
};
// Intelligent session rotation for checkout flow
middleware.checkoutSecurity = (req, res, next) => {
const timeSinceRotation = Date.now() - req.session.rotatedAt;
if (timeSinceRotation > 900000) { // 15 minutes
regenerateSession(req, res, next);
} else {
next();
}
};
// JWT-based sessions for microservices
const validateDistributedSession = async (token: string) => {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const isRevoked = await redis.exists(`revoked:${decoded.jti}`);
return !isRevoked ? decoded : null;
};
npm install express-session connect-redis redis helmet csurf rate-limiter-flexible
npm install -D @types/express-session @types/connect-redis
SESSION_SECRET=your-256-bit-secret-here
REDIS_URL=redis://localhost:6379
NODE_ENV=production
.cursorrules file/lib/session.ts with the provided helper functionsSessionData interface// Integration test with testcontainers
describe('Session Security', () => {
it('should enforce secure cookie attributes', async () => {
const response = await request(app)
.post('/login')
.send({ username: 'test', password: 'test' });
const cookie = response.headers['set-cookie'][0];
expect(cookie).toMatch(/HttpOnly/);
expect(cookie).toMatch(/Secure/);
expect(cookie).toMatch(/SameSite=lax/);
});
});
Distributed Session Management: Redis clustering with automatic failover and horizontal pod autoscaling based on operation metrics.
JWT Hybrid Architecture: Stateless tokens for microservices with server-side revocation capabilities through Redis blacklisting.
Session Analytics: OpenTelemetry integration for real-time session monitoring, anomaly detection, and capacity planning.
Zero-Downtime Key Rotation: Automated secret rotation with graceful session migration to maintain user experience during security updates.
Your session management will transform from a security liability into a competitive advantage. Stop debugging authentication edge cases and start building features that matter.
You are an expert in TypeScript, Node.js, Express.js, NestJS, Redis, JWT, TLS/HTTPS, Docker, Kubernetes, and CI/CD.
Key Principles
- Treat session identifiers as secrets; never expose them in URLs, logs, or client-side storage other than secure cookies.
- Generate session IDs with CSPRNG (`crypto.randomBytes(16)`) – ≥128 bits entropy.
- Enforce TLS (HTTPS) for every request. Terminate TLS only at trusted edges.
- Always set `Secure`, `HttpOnly`, and `SameSite=Lax|Strict` on cookies.
- Regenerate the session ID after login, privilege escalation, or every 15 min of continuous use.
- Store no PII or credentials in the session object; keep it a pointer or JWT claims only.
- Prefer stateless JWTs for micro-services; prefer server-side store (Redis) for classic MVC apps.
- Absolute timeout ≤8 h, idle timeout ≤15 min (configurable per risk tier).
- Log, alert, and revoke when a session changes IP subnet, user-agent fingerprint, or exhibits anomalous velocity.
- Cap concurrent sessions: default = 5/user, admin = 1.
TypeScript / JavaScript
- Use strict `tsconfig` (`noImplicitAny`, `exactOptionalPropertyTypes`, `strictNullChecks`).
- Define `SessionData` via `interface` and extend Express types:
```ts
declare module 'express-session' {
interface SessionData {
uid: string; // user primary key
csrfToken: string; // current CSRF token
rotatedAt: number; // unix epoch ms
meta: {
ip: string;
ua: string;
};
}
}
```
- Encapsulate session helpers in `/lib/session.ts`; export `createSession`, `regenerateSession`, `destroySession`.
- Never call `req.session.save()` inside controllers; let a central middleware persist.
- Use ES2023 `crypto.randomUUID()` only for non-secret identifiers, never for session IDs.
- Keep cookie name lowercase kebab (`sid`, `refresh-token`).
Python (Django)
- Enable `SESSION_COOKIE_SECURE`, `SESSION_COOKIE_HTTPONLY`, `SESSION_COOKIE_SAMESITE='Lax'`.
- Switch to `django-redis` cache backend for session storage; set `SESSION_ENGINE = 'django.contrib.sessions.backends.cache'`.
- Call `request.session.cycle_key()` immediately after `login()`.
Java (Spring Boot / Spring Security)
- Add `@EnableRedisHttpSession` for cluster-wide sharing.
- Configure `server.servlet.session.cookie.same-site=strict` and `server.ssl.enabled=true`.
- Use `DelegatingFilterProxy` → `SessionManagementFilter` with `migrateSession=true` on auth success.
Error Handling and Validation
- Wrap any Redis or DB call in typed `try/catch`; on failure:
• Log with structured metadata (`requestId`, `uid`, `ip`).
• Fallback to in-memory store only in non-prod.
- Validate JWT on every request: signature (HS256/RS256), `exp`, `nbf`, `iss`, `aud`, `jti` (replay). Reject clock skew >±60 s.
- Return `401` for invalid/expired sessions, never `500` – avoid information disclosure.
- Use early returns to keep happy path last.
Express.js
- Install: `npm i express-session connect-redis redis helmet csurf rate-limiter-flexible`.
- Init:
```ts
import session from 'express-session';
import connectRedis from 'connect-redis';
import { createClient } from 'redis';
const RedisStore = connectRedis(session);
const redis = createClient({ url: process.env.REDIS_URL });
app.use(session({
name: 'sid',
store: new RedisStore({ client: redis, ttl: 60 * 60 * 8 }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 1000 * 60 * 15 // 15 min idle
}
}));
```
- Add `helmet()` for common headers and `csurf()` after session.
- Middleware order: `helmet` → `cors` → `compression` → `bodyParser` → `rateLimiter` → `session` → `csrf`.
NestJS
- Use `@nestjs/platform-express` sessions or JWT via `@nestjs/jwt` + `PassportStrategy('jwt')`.
- Provide `SessionSerializer` for WebSockets/Gateways.
- Keep session guard stateless; pull user from `CacheService` by `jti` to enable revocation.
Django
- Put `django.middleware.security.SecurityMiddleware` & `django.middleware.csrf.CsrfViewMiddleware` before `SessionMiddleware`.
- Rotate `SECRET_KEY` yearly; sign out all sessions on rotation.
Performance & Scalability
- Default store: Redis, cluster mode, `maxmemory-policy allkeys-lru`, replicas ≥ 2.
- Use `SETEX sid:<id> <ttl> <payload>` instead of `HMSET` to minimize round-trips.
- Enable TCP keep-alive and TLS on Redis (`stunnel` or in-process TLS >=6.0).
- Horizontal pod autoscaling on `redis_ops_per_sec` and `app_req_per_sec`.
- JWT: keep payload ≤2 KB to reduce header bloat; compress (`zip`) only if tokens exceed 1 KB.
Security Hardening
- Enable Content Security Policy and Origin-Agent-Cluster to reduce XSS impact.
- Pin Strict-Transport-Security for 1 year preload.
- Use rotating signing keys (kid) for JWT; maintain JWKS endpoint; expire keys every 90 days.
- Implement refresh-token rotation: single-use tokens stored in Redis ado `rft:<jti>`.
- Purge sessions of deleted users via CRON job.
Testing
- Unit-test helpers with jest's fake timers for idle expiration.
- Integration tests spin up ephemeral Redis via `testcontainers`.
- Use OWASP ZAP / Burp in CI to ensure cookies flagged correctly.
- Add chaos test: kill Redis node; assert app returns 503 & does not corrupt sessions.
Observability
- Emit `session.created`, `session.regenerated`, `session.revoked` events to OpenTelemetry.
- Tag with `uid`, `jti`, `ipGeo`, anonymized where necessary.
- Build dashboards for concurrent sessions, rotation latency, anomalies/min.
Deployment & DevOps
- Secrets in Docker/K8s via `Secret` objects; deny direct env injection in logs.
- Recreate pods on secret change to load new HMAC/Signing keys.
- Run `redis-benchmark` before each release pipeline to validate capacity.
Common Pitfalls
- ✘ Storing JWT in `localStorage` → susceptible to XSS.
- ✘ Too long `maxAge` → increases hijack window.
- ✘ Using deterministic UUIDv4 RNGs → low entropy.
- ✘ Forgetting to call `req.session.regenerate()` after auth.
Reference Cheat Sheet
- Idle timeout = `cookie.maxAge` 15 min.
- Absolute timeout tracked in session payload `createdAt` + `8h`.
- Rotation frequency: on auth / privilege change / 15 min sliding.
- Concurrent limit: `ZCOUNT active:<uid> -inf +inf <= 5`.