ADR-0033: CSRF control for the BFF session — SameSite + JSON content-type¶
- Status: accepted
- Date: 2026-07-01
- Deciders: Nicolas Burri
- Refines: ADR-0011 (which listed "CSRF protection" / "a CSRF filter" as part of the posture), ADR-0028 (the cookie session)
Context¶
ADR-0011 stated the anti-theft posture would include "CSRF protection for state-changing requests"
and "a CSRF filter". A Phase-6 security review found no CSRF token filter is configured — the session
is an ambient, httpOnly, Secure, SameSite=Lax cookie (ADR-0028), and every state-changing
endpoint is a POST/PUT/DELETE under /api that consumes application/json. This ADR
records the CSRF control that is actually in force and reconciles it with ADR-0011, rather than
leaving the ADR overstating the implementation.
Decision¶
The CSRF control for the browser (BFF cookie) path is the combination of:
SameSite=Laxsession cookie (quarkus.oidc.authentication.cookie-same-site=lax) — the session cookie is not sent on cross-site subrequests; it rides only same-site requests and top-level navigations.- JSON-only content type on all mutations — state-changing endpoints require
Content-Type: application/json. A cross-origin HTML form orapplication/x-www-form-urlencodedPOST cannot forge these, and a cross-originfetch/XHR sendingapplication/jsonis subject to a CORS preflight that the server does not answer for foreign origins (no permissive CORS config).
This is a recognized CSRF mitigation for cookie-authenticated JSON APIs; a dedicated synchronizer-token
filter (e.g. quarkus-csrf-reactive) is not used, because it would add a token round-trip the SPA
must thread through every mutation for marginal additional protection given (1)+(2).
Consequences¶
- ADR-0011's "CSRF filter" wording is superseded by this ADR: the control is (1)+(2), not a token filter. No code change results from this ADR — it documents the accepted control.
- If a future requirement (e.g. a stricter audit finding, or relaxing to cross-site usage / permissive
CORS) demands it, add
quarkus-csrf-reactiveand have the SPA send the CSRF token on mutations — that would be its own ADR superseding this one. - Guardrail: do not introduce permissive CORS or accept non-JSON bodies on mutating endpoints without revisiting this decision, as either would weaken control (2).