Skip to main content
InternalMarkdown

ADR 0016. BFF Cookie Sessions and Machine OAuth

Status​

Accepted.

Supersedes ADR 0003 (signed JWT at operator login for an embedded widget). Gameplay independence is ADR 0015.

Context​

A partner-readable session JWT on every game action would put PlayerPal claims in the hot path, encourage putting PII or live balance in tokens, and depend on third-party cookies for widgets. Browser localStorage refresh tokens are a theft target.

Decision​

Player web: Authorization Code + PKCE through a backend-for-frontend. Session is an HttpOnly, Secure, SameSite cookie. The browser token, if any, carries the IAM subject, not the private player UUID and not live loyalty state. Mapping iss + sub → player is server-side.

Embedded operator/provider UX: first-party PlayerPal popup, opaque one-time codes, exact postMessage origin checks. No assertion or access token in URLs. No third-party cookies. No refresh tokens in the widget.

Machine clients: OAuth 2.0 client credentials with private_key_jwt. Access-token lifetime 5-15 minutes. Cached JWKS for validation. Key overlap during rotation.

Consequences​

  • Claim-set and token-lifetime open questions from ADR 0003 are closed for the profiles above (spec §13).
  • Embedded widgets cannot silently keep a PlayerPal session after popup close.
  • See docs/authentication.md and spec §14.

Amendment​

Local POC also establishes the BFF cookie via Nest Session/User API password and passkey flows and Nest-owned social IdP success (ADR 0024), not only Auth Code + PKCE through Login V2. Cookies must be first-party on the portal host (player.localhost path-routed Nest).