Skip to main content

Configuring cookies

Ory Hydra uses HTTP cookies for login CSRF, consent CSRF, device-flow CSRF, and the user authentication session. This guide covers how to tune their SameSite mode, domain, path, names, and development-mode flags.

SameSite mode

The serve.cookies.same_site_mode setting controls the SameSite attribute. Allowed values are Strict, Lax, or None. The default is None.

serve:
cookies:
same_site_mode: Lax

Pick the strictest value your deployment can tolerate:

  • Strict — cookies are only sent on same-site requests. Safest, but breaks cross-site redirects back into Hydra (for example, returning from an external login UI on a different eTLD+1).
  • Lax — cookies are sent on top-level navigations. Good default when the login/consent UI and Hydra share a parent domain (see serve.cookies.domain below).
  • None — cookies are sent on all cross-site requests. Required when Hydra is reached cross-site, for example by front-channel logout iframes rendered on a different eTLD+1 than Hydra. SameSite=None requires the Secure flag, so it only works over HTTPS. If the issuer URL isn't HTTPS, Hydra falls back to Lax at runtime.
Third-party cookie deprecation

Modern browsers restrict or block third-party cookies regardless of SameSite=None:

Host Hydra on the same eTLD+1 as your application and use SameSite=Lax whenever possible. For cross-domain logout, prefer back-channel logout over front-channel logout iframes. Embedding the login, consent, or other authentication flows themselves inside an iframe isn't supported.

Legacy SameSite=None workaround

Browsers released before 2020 (Chrome < 80, old iOS 12 / macOS 10.14 Safari, UC Browser, and a handful of embedded WebViews) reject cookies with SameSite=None. Hydra can work around this by writing a second cookie without the SameSite attribute for those clients. Enable it with serve.cookies.same_site_legacy_workaround: true. It only takes effect when same_site_mode is None.

# SameSite=None requires Secure, so TLS must be enabled (dev: false).
dev: false

serve:
cookies:
same_site_mode: None
same_site_legacy_workaround: true

This flag exists for backwards compatibility with legacy user agents. If you don't need to support pre-2020 browsers, leave it disabled.

Set the cookie domain with serve.cookies.domain. This scopes the session and CSRF cookies to a parent domain so they can be shared with subdomains (for example, your login/consent UI on auth.example.com and Hydra on hydra.example.com).

serve:
cookies:
domain: example.com

Only set this when you control every subdomain the cookie will be sent to.

Scope the session cookie to a specific path with serve.cookies.paths.session. The default is /.

serve:
cookies:
paths:
session: /

Override the default cookie names with serve.cookies.names:

serve:
cookies:
names:
login_csrf: my_login_csrf
consent_csrf: my_consent_csrf
device_csrf: my_device_csrf
session: my_session

Defaults:

KeyDefaultPurpose
login_csrfory_hydra_login_csrfCSRF protection for the login flow.
consent_csrfory_hydra_consent_csrfCSRF protection for the consent flow.
device_csrfory_hydra_device_csrfCSRF protection for the OAuth 2.0 device authorization flow.
sessionory_hydra_sessionAuthenticated user session between login/consent interactions.

Secure flag in development

In production, Hydra always sets the Secure cookie attribute. When running with dev: true (no TLS), Secure is dropped so cookies work over plain HTTP. Override this with serve.cookies.secure: true — useful if you terminate TLS at a reverse proxy and run Hydra itself over HTTP:

dev: true

serve:
cookies:
secure: true

In development mode, CSRF and session cookie names are suffixed with _dev (for example, ory_hydra_session_dev) so they don't collide with production cookies on the same domain.