Cookie-session auth (same-origin) #30
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Same-origin cookie-session authentication via Symfony security (no JWT — no mobile/3rd-party clients planned).
security.yaml: form-login/authenticator, HttpOnly + Secure + SameSite=Lax session cookie.meendpoints under/api.Exit: can log in/out via the API; authenticated requests carry the session cookie; covered by functional tests.
CSRF scope clarification (2026-06-18)
The original plan was to add stateless double-submit CSRF tokens on
/api/loginviajson_login'senable_csrfoption. While implementing, we verified against theJsonLoginFactory/AbstractFactorysource thatjson_loginhas noenable_csrfoption — it's aform_login/logout-only key./api/loginis owned entirely by the firewall'sJsonLoginAuthenticator(no controller in front), so there's no natural CSRF-token attachment point.Cross-checked the current (2026) recommended approach for a same-origin React SPA + Symfony cookie-session stack (SymfonyCasts "React with Symfony" CSRF course + Symfony docs). The mainstream pattern does not put a CSRF token on the login endpoint; it protects login (and all mutating requests) with:
SameSite=Laxsession cookie (+ HttpOnly + Secure),Content-Type: application/jsonenforcement on mutating requests — a cross-site form/<img>CSRF can't set that header without a CORS preflight, which same-origin policy blocks.json_loginalready requires a JSON body, so this is free.Resolution for this ticket: login's CSRF defense = SameSite=Lax + HttpOnly + Secure + JSON-Content-Type. No CSRF token on login. Explicit stateless double-submit CSRF is deferred to the first ticket introducing a mutating resource endpoint, where API Platform controllers provide a proper
#[IsCsrfTokenValid]attachment point.This narrows #30's CSRF scope but matches the current recommended pattern for this architecture. Exit criteria otherwise unchanged.
Follow-up: deferred stateless CSRF is now WON'T-DO (superseded by SameSite)
This ticket deferred "explicit stateless double-submit CSRF" to the first mutating-resource ticket (#31). Revisited during #31 planning and decided not to build it at all for this app:
SameSite=Laxon the session cookie means the browser does not attach the cookie to cross-site state-changing requests — which is the CSRF vector — so a forged cross-site write arrives unauthenticated. Combined with API Platform requiringContent-Type: application/jsonon writes (a classic CSRF can't set that header cross-origin without a CORS preflight our same-origin policy blocks) and this being a same-origin-only SPA with no 3rd-party/mobile clients, explicit CSRF tokens defend a vector already fully blocked.Instead, #31 adds a regression-guard test that mutating
/apiwrites requireapplication/json, documenting the protection. Explicit tokens would only become relevant if the app ever adoptedSameSite=None(cross-site embedding) — which it deliberately won't. No CSRF-token ticket will be opened.