# ADR 0003. Authenticate at a Boundary Point, Not Per-Action

## Status
Superseded by [ADR 0015](0015-async-loyalty-sidecar.md) (PlayerPal is off the
game path) and [ADR 0016](0016-bff-cookies-and-machine-oauth.md) (BFF cookies,
popup linking, machine OAuth).

The original "signed JWT at operator login for an embedded widget" model is
not current. Identity is still resolved at a control-plane boundary, not per
gameplay action. That part stands, but the token and transport design does not.

## Context
Gameplay actions can be extremely high frequency. Requiring PlayerPal
identity resolution (a DB lookup) on every action would put PlayerPal in
the critical path of gameplay, adding latency, cost, and a failure
coupling that shouldn't exist.

## Decision
Resolve/authenticate identity once, at a boundary point (operator login),
and issue a short-lived **signed JWT** carrying scoped claims. Both the
operator/app and the embedded PlayerPal widget can read it without a
fresh DB hit. The token stays small, avoids sensitive PII, and excludes
fast-changing state (e.g. live balance). That is fetched separately via
`GET /v1/me/loyalty`.

## Consequences
- No DB lookup per gameplay action; gameplay stays fast and decoupled
  from PlayerPal's availability.
- Token content is a trade-off: richer claims reduce round-trips but
  increase staleness risk and token size. Claim set is not yet finalized.
- Revocation is harder with self-contained JWTs than with server-side
  sessions. Token lifetime needs to be short enough that this is
  acceptable (still an open decision).
