4.1 KiB
identity-on-sx: OAuth2, sessions & membership on Erlang
DRAFT outline. The identity core
acl-on-sxassumes already exists.aclanswers "may X do Y"; identity answers "who is X, and how did they prove it." Depends onpersist-on-sx(grant/audit ledger). Pairs withacl-on-sx.
rose-ash's account domain is the OAuth2 authorization server every other app is
a client of: silent SSO, per-app first-party cookies, grant verification,
membership. Sessions and grants are long-lived, concurrent, individually
addressable, and expire on their own — that is the actor model. Erlang's
processes + mailboxes map cleanly: a session is a process, token issue/refresh/
revoke are messages, expiry is a process timeout, and SSO is one process answering
many apps.
End-state: an Erlang-on-SX layer with the OAuth2 authorization-code + silent
(prompt=none) flows as message protocols, a session/grant registry, token
lifecycle (issue/refresh/revoke/introspect), and membership state — all auditable
through the event log, all authorization questions delegated to acl-on-sx.
Status (rolling)
bash lib/identity/conformance.sh → 0/0 (not yet started)
Ground rules
- Scope: only
lib/identity/**andplans/identity-on-sx.md. May import fromlib/erlang/, and (once they exist)lib/persist/+lib/acl/. Do not edit substrates. - Architecture: a session/grant is a process holding its own state; the
registry routes messages by subject/client id. Tokens are opaque + introspected,
not self-validating (revocation must be real). Authorization decisions are NOT
made here —
identityproves identity,acldecides permission. - Security: revocation is immediate (kill the process / tombstone the grant); no decision relies on a token that outlived its grant. Negative answers are explicit, never "absence of a yes."
- Commits: one feature per commit. Progress log + tick boxes.
Architecture sketch
Auth request Token / session
(authorize client scope subject) {:access :refresh :expires :grant}
│ ▲
▼ │
lib/identity/oauth.sx lib/identity/token.sx
— authz-code + prompt=none flows — issue / refresh / revoke / introspect
— as Erlang message protocols — opaque tokens, grant-backed
│ ▲
▼ │
lib/identity/session.sx lib/identity/registry.sx
— session = process, expiry=timeout — route by subject/client; SSO fan-out
│ │
▼ ▼
lib/identity/api.sx ── (identity/login) (identity/grant?) (identity/revoke) ──┐
│ │
└──────── grant + audit events → persist ; permission? → acl ──────────┘
Phase 1 — Sessions + tokens
session.sx— session process, create/lookup/expiretoken.sx— issue/introspect/revoke (opaque, grant-backed)registry.sx— route by subject/clientapi.sx+ tests + scoreboard + conformance.sh
Phase 2 — OAuth2 flows
- authorization-code flow as a message protocol
- refresh + rotation; revocation cascades to issued tokens
- tests: full code exchange, refresh, revoke-then-use (must fail)
Phase 3 — Silent SSO + membership
prompt=nonecross-app login (one session, many clients)- membership state + per-app grant projection
- grant verification delegated cache (mirror Redis-cache pattern)
Phase 4 — Audit + federation
- every issue/refresh/revoke is a
persistevent;(identity/audit subject) - federated identity (peer-asserted subject) — advisory, trust-gated stub
- tests: audit completeness, cross-instance subject mapping
Progress log
(loop fills this in)
Blockers
(loop fills this in)