Olympus Docs
SecurityWeb attacks

CSRF defense

Cross-site request forgery, what Olympus does, what you do

CSRF is an attack where a malicious site causes a logged-in user's browser to make a request to your app that has side effects (transfer money, change password, delete data).

What Olympus does

Kratos flows

Every login, registration, recovery, settings, and verification flow includes a CSRF token. Kratos generates it, embeds it in the flow's HTML form, and verifies it on submission.

You see this in Hera's forms: a hidden <input type="hidden" name="csrf_token" value="..."> is part of every form.

If the user submits without the token (or with a stale one), Kratos rejects: 400 Bad Request with csrf_violation.

OAuth2 authorization endpoint

OAuth2's defense is the state parameter: client generates a random value, sends it on /oauth2/auth, expects it back on the callback. If state doesn't match, your client rejects.

For public clients, PKCE is also a defense (the code_verifier is a secret the attacker doesn't have).

What you should do

Your app's mutation endpoints

API endpoints that change state (POST, PUT, DELETE) need protection if they accept cookie-based auth. Two patterns:

Pattern A: Bearer-only. If your API only accepts Authorization: Bearer ... and never cookies, CSRF doesn't apply. The attacker's site can't read your token (cross-origin) and can't send it.

Pattern B: Cookies + CSRF token. If you use cookies (e.g., a same-origin BFF), implement a CSRF token. Options:

  1. Synchronizer token: server issues a token on first page load, stores in session, validates on each mutation.
  2. Double-submit cookie: server sets a cookie, client mirrors it in a header. Compare server-side. Simpler, stateless. Olympus's bridge sessions use this.
  3. SameSite=Strict cookies: not sent on cross-site requests at all. Caveat: breaks legitimate cross-tab flows.

Frontend frameworks

  • Next.js Server Actions include built-in CSRF protection (origin check).
  • React Router actions require manual implementation.
  • HTMX has hx-headers for adding tokens.

Don't rely on Origin header alone

Origin and Referer can be missing in some browsers / contexts. Use them as a secondary check, never the only one.

Olympus sets all auth cookies with SameSite=Lax:

  • Cookie is sent on top-level GET navigations (so links to your app work).
  • Cookie is NOT sent on cross-site POST/PUT/DELETE (so CSRF mostly impossible).

SameSite=Strict is stricter but breaks the OAuth2 redirect-back flow (Hydra → your app via 302 from another origin, cookies blocked).

SameSite=None would re-enable CSRF, only use with explicit Secure flag and only when iframe embedding is needed.

CORS is not CSRF defense

CORS controls JavaScript reading responses, not browser-issued requests. A <form> submit cross-origin is allowed by CORS but is still CSRF, you need a token.

Testing your CSRF defense

# From a different origin, attempt a mutation:
curl -X POST https://your-app.com/api/transfer \
  -H "Cookie: session=stolen" \
  -d "amount=1000"

Should return 403 with csrf_violation.

On this page