/** * State Parameter Utilities for CSRF Protection * * Provides cryptographically secure state parameter generation * and constant-time comparison for OAuth CSRF protection. */ import crypto from "crypto"; /** * Generate a cryptographically secure state parameter * * Creates a 32-byte random state parameter for CSRF protection * in OAuth flows. This state is stored in the session and must * match when the OAuth provider redirects back. * * @returns Hex-encoded 32-byte random string (64 characters) */ export function generateState(): string { return crypto.randomBytes(32).toString("hex"); } /** * Validate state parameter using constant-time comparison * * Compares the provided state with the stored state using a * constant-time algorithm to prevent timing attacks. * * @param provided - State parameter from OAuth provider callback * @param stored - State parameter stored in session * @returns true if states match, false otherwise */ export function validateState(provided: string, stored: string): boolean { if (!provided || !stored) { return false; } // Ensure both strings are the same length to prevent timing attacks if (provided.length !== stored.length) { return false; } try { // Use Node.js crypto.timingSafeEqual for constant-time comparison const providedBuffer = Buffer.from(provided, "utf8"); const storedBuffer = Buffer.from(stored, "utf8"); // Both buffers must be same length for timingSafeEqual if (providedBuffer.length !== storedBuffer.length) { return false; } return crypto.timingSafeEqual(providedBuffer, storedBuffer); } catch (error) { // If comparison fails for any reason, return false return false; } } /** * Generate a session ID for OAuth flow tracking * * Creates a unique session identifier for correlating OAuth * initiation with callback. * * @returns Hex-encoded random string */ export function generateSessionId(): string { return crypto.randomBytes(16).toString("hex"); }