typescriptintermediate

Secure Cookie and Session Management

Handle HTTP cookies with signing, encryption, and session management using secure defaults.

typescript
import crypto from 'crypto';
import type { IncomingMessage, ServerResponse } from 'http';

function parseCookies(req: IncomingMessage): Record<string, string> {
  const header = req.headers.cookie ?? '';
  return Object.fromEntries(
    header.split(';').map(c => {
      const [key, ...rest] = c.trim().split('=');
      return [key, decodeURIComponent(rest.join('='))];
    }).filter(([k]) => k),
  );
}

interface CookieOptions {
  httpOnly?: boolean;
  secure?: boolean;
  sameSite?: 'Strict' | 'Lax' | 'None';
  maxAge?: number;
  path?: string;
  domain?: string;
}

function setCookie(
  res: ServerResponse,
  name: string,
  value: string,
  options: CookieOptions = {},
) {
  const {
    httpOnly = true,
    secure = true,
    sameSite = 'Lax',
    maxAge = 86400,
    path = '/',
  } = options;

  const parts = [`${name}=${encodeURIComponent(value)}`];
  parts.push(`Path=${path}`);
  parts.push(`Max-Age=${maxAge}`);
  parts.push(`SameSite=${sameSite}`);
  if (httpOnly) parts.push('HttpOnly');
  if (secure) parts.push('Secure');
  if (options.domain) parts.push(`Domain=${options.domain}`);

  const existing = res.getHeader('Set-Cookie') as string[] | undefined;
  const cookies = existing ? [...existing, parts.join('; ')] : [parts.join('; ')];
  res.setHeader('Set-Cookie', cookies);
}

// Signed cookies
const SECRET = process.env.COOKIE_SECRET ?? 'change-me';

function sign(value: string): string {
  const sig = crypto.createHmac('sha256', SECRET).update(value).digest('base64url');
  return `${value}.${sig}`;
}

function unsign(signed: string): string | null {
  const idx = signed.lastIndexOf('.');
  if (idx < 0) return null;
  const value = signed.slice(0, idx);
  const expected = sign(value);
  return crypto.timingSafeEqual(Buffer.from(signed), Buffer.from(expected)) ? value : null;
}

// Session store (in-memory for demo)
const sessions = new Map<string, { data: Record<string, unknown>; expires: number }>();

function createSession(data: Record<string, unknown>, ttl = 3600): string {
  const id = crypto.randomUUID();
  sessions.set(id, { data, expires: Date.now() + ttl * 1000 });
  return id;
}

function getSession(id: string): Record<string, unknown> | null {
  const s = sessions.get(id);
  if (!s || Date.now() > s.expires) { sessions.delete(id); return null; }
  return s.data;
}

export { parseCookies, setCookie, sign, unsign, createSession, getSession };

Sponsored

Auth0

Use Cases

  • Authentication session handling
  • Secure cookie management
  • Stateful server applications

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.