Declare Joystick in the Idunn recipe and document the locked refresh
Recipe optional_environment gains the Joystick client id and secret file; service-contract documents the row lock, rotation fail-closed and the 410/502 answers; the StreamPixels profile names Heimdall as sole holder of provider refresh tokens (F5). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
43b7072dfb
commit
3eaa9ef265
3 changed files with 30 additions and 6 deletions
|
|
@ -157,6 +157,8 @@ optional_environment = [
|
|||
"GC_ACCESS_PROVIDER_DISCORD_CLIENT_ID",
|
||||
"GC_ACCESS_PROVIDER_DISCORD_CLIENT_SECRET_FILE",
|
||||
"GC_ACCESS_PROVIDER_GITHUB_CLIENT_SECRET_FILE",
|
||||
"GC_ACCESS_PROVIDER_JOYSTICK_CLIENT_ID",
|
||||
"GC_ACCESS_PROVIDER_JOYSTICK_CLIENT_SECRET_FILE",
|
||||
"GC_ACCESS_PROVIDER_PATREON_CLIENT_ID",
|
||||
"GC_ACCESS_PROVIDER_PATREON_CLIENT_SECRET_FILE",
|
||||
"GC_ACCESS_PROVIDER_SPOTIFY_CLIENT_SECRET_FILE",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@ Corroborated by `gamecult-ops/nginx/streampixels.gamecult.org.conf:14`
|
|||
The current StreamPixels architecture already makes useful splits:
|
||||
|
||||
- the web app owns the remembered viewer session
|
||||
- the service owns provider OAuth exchange and identity resolution
|
||||
- Heimdall owns provider OAuth exchange, identity resolution and refresh-token
|
||||
custody for Twitch, YouTube and Joystick; StreamPixels never calls a provider
|
||||
token endpoint and holds no provider refresh token. It asks Heimdall for a
|
||||
short-lived access token (`managed-credentials/resolve`) and treats `410
|
||||
managed_credential_revoked` as "the creator must reconnect"
|
||||
- the overlay remains auth-free
|
||||
- creator memberships and operator roles are separate from general viewer state
|
||||
|
||||
|
|
@ -38,7 +42,7 @@ In the service-first Heimdall version, the most likely reusable slice is:
|
|||
|
||||
- provider OAuth authority
|
||||
- identity-linking authority
|
||||
- managed Twitch/YouTube credential custody for creator connections
|
||||
- managed Twitch/YouTube/Joystick credential custody for creator connections (Joystick is a managed connection only, not a viewer sign-in provider)
|
||||
- entitlement refresh
|
||||
- shared claim semantics
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ Supported providers in the skeleton:
|
|||
- `twitch`
|
||||
- `youtube`
|
||||
- `spotify`
|
||||
- `joystick`
|
||||
|
||||
Request body:
|
||||
|
||||
|
|
@ -430,9 +431,11 @@ Important behavior:
|
|||
|
||||
- the refresh token is signed by Heimdall and scoped to one app session
|
||||
- the access token remains short-lived; app backends still verify it locally
|
||||
- if a stored provider access token is expired or near expiry, Heimdall uses
|
||||
the stored provider refresh token and persists any rotation before
|
||||
evaluating entitlements
|
||||
- if a stored provider access token is expired or near expiry, Heimdall takes
|
||||
a row lock on the linked identity, re-reads it, uses the stored provider
|
||||
refresh token and persists any rotation before evaluating entitlements; an
|
||||
identity whose grant the provider has revoked (no stored access token)
|
||||
contributes no entitlement
|
||||
- any app authenticated via `x-heimdall-app-secret` (`resolveAppCaller`) may
|
||||
send `entitlementPolicies`; Heimdall matches each stored identity to the
|
||||
policy for that provider. Sending policy without authenticating is
|
||||
|
|
@ -484,7 +487,22 @@ Important behavior:
|
|||
- it returns access tokens only; refresh tokens remain in Heimdall custody
|
||||
- when a stored managed credential is expired or within the refresh window,
|
||||
Heimdall refreshes it before returning the access token and persists rotated
|
||||
access/refresh tokens
|
||||
access/refresh tokens. The refresh runs under a row lock on the linked
|
||||
identity (`SELECT ... FOR UPDATE`), so a given refresh token is presented to
|
||||
the provider once across concurrent requests and across two Heimdall
|
||||
processes sharing one database. The provider call is bounded at 10 seconds
|
||||
- a provider whose refresh tokens rotate (Joystick) fails closed: a refresh
|
||||
response without a new refresh token revokes the credential instead of
|
||||
keeping the old token
|
||||
- `410 {"error":"managed_credential_revoked","provider":...}`: the provider
|
||||
rejected the grant (`invalid_grant`), or the identity holds no access token.
|
||||
The stored tokens are cleared and an audit event `managed_credential_revoked`
|
||||
is written; the owner must reconnect. `404 managed_credential_not_found`
|
||||
means no linked identity exists
|
||||
- `502 {"error":"managed_credential_refresh_failed","provider":...}`: the
|
||||
refresh failed for any reason that is not a grant verdict (invalid client,
|
||||
provider 5xx, timeout, malformed body). Stored tokens are untouched and a
|
||||
later request may succeed
|
||||
- app-local binding, diagnostics, subscription setup, and runtime behavior stay
|
||||
app-owned
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue