0017. Browser integration: external login UI and headless transactions#
Status: Accepted
Context#
The product delivers no login pages or admin dashboard (§1.2), yet browser redirects, CSRF defenses and session cookies remain backend responsibilities. A "headless" API must not become a password-to-token shortcut (§1.2, AUT-003).
Decision#
- The authorization endpoint validates the request, starts a server-side
authentication transaction and redirects the browser to the configured login UI
(
clients.login_ui_url, else realminteraction.login_ui_url) with onlytransaction_idandrealmin the URL. The continuation secret is set as an HttpOnly cookiepa_tx, originally scoped to/api/v1/realms/{realm}/auth/and since the 2026-10 update to the transaction's own path (/api/v1/realms/{realm}/auth/transactions/{id}), so concurrent transactions in one browser do not overwrite each other (AUT-016). - The login UI drives
/api/v1/realms/{realm}/auth/transactions/{id}/...steps. Browser callers authenticate steps with the cookie plus anX-CSRF-Tokenderived from the continuation and an allowedOrigin(the public origin or a registered client origin). Headless callers (backends, CLIs) start transactions withPOST /auth/transactionsand send the continuation inX-Transaction-Token. - Completion yields an authorization code in
redirect_to; tokens are only obtainable by the client with its PKCE verifier at the token endpoint. - Browser applications are encouraged to use a backend-for-frontend that keeps
tokens server-side (
examples/backend-for-frontend,proudauth-sdk-go/oidcclient). - IdP session cookie
pa_sid(HttpOnly,Secureunlesssessions.cookie_insecure_dev, SameSite fromsessions.cookie_same_site, defaultlax) is scoped to/realms/{realm}/and enables SSO at the authorization endpoint.
Alternatives considered#
- Bundled hosted login pages: out of scope by product definition.
- Token-returning headless login: rejected (§18.2).
Consequences#
- Each deployment must provide a login UI for browser flows; without one the
authorization endpoint returns
temporarily_unavailableand only the headless API works. - The device flow's
verification_uriis the client'slogin_ui_url, else the realm's login UI URL; when neither is set, device authorization requests are refused withinvalid_request(the server has no/devicepage). - Browser-mode registration uses the transaction-scoped route
POST /api/v1/realms/{realm}/auth/transactions/{id}/registration, which lies inside the per-transaction cookie path; the realm-levelPOST /api/v1/realms/{realm}/registrationsserves headless clients that sendX-Transaction-Token. - The full step reference is in docs/protocols/headless-authentication.md.
Migration implications#
Changing cookie names, paths or the CSRF derivation breaks in-flight transactions only (10-minute lifetime) but requires login UI updates.
Related requirement IDs#
AUT-001..AUT-008, AUT-016, AUT-020, SES-010, SEC-002, SEC-003, SDK-004, §1.2, §9.1, §28.4