/** * @module @arcis/node/middleware/csrf * CSRF (Cross-Site Request Forgery) protection middleware * * Implements the double-submit cookie pattern: * 1. Server sets a CSRF token in a cookie * 2. Client must send the same token in a header or form field * 3. Middleware rejects requests where cookie token !== header/field token * * This works because an attacker's cross-origin form submission will include * the cookie automatically, but cannot read it (same-origin policy) to set * the matching header. */ import type { Request, Response, NextFunction, RequestHandler } from 'express'; /** CSRF protection configuration */ export interface CsrfOptions { /** Cookie name for the CSRF token. Default: '_csrf' */ cookieName?: string; /** Header name to check for the token. Default: 'x-csrf-token' */ headerName?: string; /** Form field name to check for the token. Default: '_csrf' */ fieldName?: string; /** Token byte length (hex-encoded = 2x chars). Default: 32 */ tokenLength?: number; /** HTTP methods to protect. Default: ['POST', 'PUT', 'PATCH', 'DELETE'] */ protectedMethods?: string[]; /** Paths to exclude from CSRF checks (e.g., webhook endpoints) */ excludePaths?: string[]; /** * Per-request skip function. If it returns true, CSRF check is skipped * for that request. Useful for API key auth or signed webhooks. * * @example * skipCsrf: (req) => Boolean(req.headers['x-api-key']) */ skipCsrf?: (req: Request) => boolean; /** * Use the __Host- cookie prefix for stronger cookie security. * When enabled, the browser enforces: Secure=true, no Domain, Path=/. * This prevents CSRF cookie theft across subdomains. * Default: false */ useHostPrefix?: boolean; /** Cookie options */ cookie?: { /** Cookie path. Default: '/' */ path?: string; /** HttpOnly — set false so client JS can read it for headers. Default: false */ httpOnly?: boolean; /** Secure flag (HTTPS only). Default: true in production */ secure?: boolean; /** SameSite attribute. Default: 'Lax' */ sameSite?: 'Strict' | 'Lax' | 'None'; /** Cookie domain */ domain?: string; }; /** Custom error handler when CSRF validation fails */ onError?: (req: Request, res: Response, next: NextFunction) => void; /** * Rotate the CSRF token after each successful validation on a protected * method. Defends against token-fixation attacks where an attacker plants * a known token before authentication. Default: false. * * When enabled, every successful POST/PUT/PATCH/DELETE causes the server to * issue a fresh token via Set-Cookie — the client must re-read the cookie * before the next mutating request. */ rotateOnUse?: boolean; } /** * Generate a cryptographically random CSRF token. * * @param length - Byte length (output is hex, so 2x chars). Default: 32 * @returns Hex-encoded random token * * @example * const token = generateCsrfToken(); // 64 hex chars */ export declare function generateCsrfToken(length?: number): string; /** * Validate that two CSRF tokens match using constant-time comparison. * * @param cookieToken - Token from the cookie * @param requestToken - Token from the header or form field * @returns true if tokens match */ export declare function validateCsrfToken(cookieToken: string, requestToken: string): boolean; /** * Create CSRF protection middleware using double-submit cookie pattern. * * For safe methods (GET, HEAD, OPTIONS), sets a CSRF token cookie if not present. * For unsafe methods (POST, PUT, PATCH, DELETE), validates the token. * * @param options - CSRF configuration * @returns Express middleware * * @example * // Basic usage * app.use(csrfProtection()); * * @example * // Exclude webhook paths * app.use(csrfProtection({ * excludePaths: ['/api/webhooks/stripe', '/api/webhooks/github'] * })); * * @example * // Client-side: read cookie + set header * const token = document.cookie.match(/_csrf=([^;]+)/)?.[1]; * fetch('/api/data', { * method: 'POST', * headers: { 'X-CSRF-Token': token }, * credentials: 'same-origin' * }); */ export declare function csrfProtection(options?: CsrfOptions): RequestHandler; /** Alias for csrfProtection */ export declare const createCsrf: typeof csrfProtection; //# sourceMappingURL=csrf.d.ts.map