/** * Copyright (c) 2026 AzerothJS. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import type { EdgeMiddleware } from './edge.ts'; import type { GuardContext } from './api/declare.ts'; /** Shared knobs for {@link csrfCookie} and {@link csrfProtect} - pass the SAME object to both. */ export interface CsrfOptions { /** Cookie name. Default `__Host-azcsrf` when secure, `azcsrf` when `secure: false`. */ cookie?: string; /** The header the caller mirrors the cookie into. Default `x-azeroth-csrf`. */ header?: string; /** * Emit the Secure cookie under the `__Host-` prefix (default true). Set false ONLY for * plain-http development - the prefix is what pins the cookie to this exact host. */ secure?: boolean; /** Origins beyond the request's own (`scheme://host[:port]`, exact) allowed to submit. */ allowedOrigins?: readonly string[]; } /** Mints one token: 32 random bytes as base64url. */ export declare function csrfToken(): string; /** * Edge middleware minting the token cookie on GET responses that arrive without one. The * cookie is deliberately readable (httpOnly false): double submit works BECAUSE the page's * own JS can read it and a cross-site attacker cannot. */ export declare function csrfCookie(options?: CsrfOptions): EdgeMiddleware; /** * The CSRF guard: rejects a state-changing request unless its origin checks out AND the * cookie token is mirrored in the header. A plain guard - compose it anywhere the chain * runs: `feature('/x', [csrfProtect(csrf)], ...)`, `routes.with(csrfProtect(csrf))`, or * `app.with(csrfProtect(csrf))`. Reads headers only, never the body, so it can never trip * the body-consumed check downstream. */ export declare function csrfProtect(options?: CsrfOptions): (context: GuardContext) => void; /** The hidden input a no-JS form carries its CSRF token in. */ export declare const CSRF_FIELD = "_csrf"; /** * Verifies a request whose CSRF token arrives in the BODY rather than a header. * * A plain HTML form cannot set a header, so the header guard - which documents itself as * reading headers only, and must keep that promise or it would consume a body the handler * still needs - structurally cannot cover a no-JS submit. The caller here has already parsed * the body, so it hands the field value over and no second read happens. * * Same two checks, same order, same errors as {@link csrfProtect}: origin first, then the * mirrored token. Safe methods never reach this - a form submit is a POST by construction. * * @param request - The submitting request; its cookies carry the authoritative token. * @param url - The request's own URL, for the origin comparison. * @param submitted - The token the form carried, or null when the field was absent. * @param options - The same cookie/origin options the guard takes. * @throws {ForbiddenError} On a cross-site origin or a missing/mismatched token. */ export declare function verifyCsrfField(request: Request, url: URL, submitted: string | null, options?: CsrfOptions): void;