# `csrf-policy` — `CsrfPolicy.requiresCsrf` _(no submodules)_ ## Purpose Exposes a single pure predicate, `CsrfPolicy.requiresCsrf(scheme)`, that defaults CSRF protection ON for any cookie-based scheme and OFF for any scheme where the caller must actively attach the credential. This default codifies the design-doc §6 rule "Cookie-based auth adapters trigger CSRF verification" so every concrete adapter inherits the right behaviour without restating it. The package exposes only the default; the host (`api-host`) applies per-route `csrf: false` overrides on top. Keeping the default and the override separate means a route-level opt-out is always auditable as an explicit decision in the manifest, never a side-effect of which adapter happened to be wired. ## Features - Pure function — no side effects, no module-load cost. - Frozen container object so test code can `expect(CsrfPolicy)` reliably and consumers cannot monkey-patch the predicate. - Total over the `OpenApiSecurityScheme` discriminated union — no `default` branch means an added scheme type at the schema layer will surface a type-level reminder to revisit the policy. ## Usage: Basic ```ts import { CsrfPolicy } from "@suaveplan/api-auth/csrf-policy"; const needsCsrf = CsrfPolicy.requiresCsrf({ type: "apiKey", in: "cookie", name: "sp_session", }); // → true ``` ## Usage: Advanced Drive a host-side CSRF middleware off the policy, with a per-route override applied at the call site: ```ts import { CsrfPolicy } from "@suaveplan/api-auth/csrf-policy"; import type { OpenApiSecurityScheme } from "@suaveplan/api-auth/security-scheme"; interface RouteCsrfDecision { readonly required: boolean; readonly reason: "scheme-default" | "route-override"; } function decideCsrf( scheme: OpenApiSecurityScheme, routeOverride: boolean | undefined, ): RouteCsrfDecision { if (routeOverride !== undefined) { return { required: routeOverride, reason: "route-override" }; } return { required: CsrfPolicy.requiresCsrf(scheme), reason: "scheme-default", }; } const decision = decideCsrf( { type: "http", scheme: "bearer" }, undefined, ); // → { required: false, reason: "scheme-default" } ``` ## API Reference | Symbol | Kind | Description | |----------------------------|-------------|----------------------------------------------------------| | `CsrfPolicy.requiresCsrf` | function | `(scheme) => boolean`. Cookie schemes → `true`. | ## Implementation Notes - The predicate inspects `type === "apiKey" && in === "cookie"` — apiKey-in- header is treated identically to `Authorization: Bearer …` for CSRF purposes because the caller must attach it explicitly. - `oauth2` and `openIdConnect` default OFF — both are bearer-token-derived in practice; if a deployment exposes an oauth2 access token via cookie, that's a custom apiKey-in-cookie scheme, not the `oauth2` scheme. - `Object.freeze` guards the predicate slot; the predicate itself is a regular method and TypeScript prevents reassignment via the `Readonly` inference.