identity: access-token TTL via logical clock — expires_in (RFC 6749 §4.2.2, +8 tests)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 22s

The token registry holds a logical clock (advance/now; the substrate has no
wall clock). Grants carry a Ttl; each access token carries an Expires
(Now-at-issue + Ttl, or infinity); introspect returns inactive once Now
reaches it. Refresh mints a fresh short-lived access token — short access
tokens, long refresh tokens. issue/4 and issue_grant/4 default to infinity so
all prior behaviour is unchanged. New tests/expiry.sx. token loop/6. 138/138.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 01:53:19 +00:00
parent e951f23f14
commit a43825f25f
6 changed files with 137 additions and 30 deletions

View File

@@ -19,7 +19,7 @@ through the event log, all authorization questions delegated to `acl-on-sx`.
## Status (rolling)
`bash lib/identity/conformance.sh`**130/130** (4 phases + ext: scope narrowing)
`bash lib/identity/conformance.sh`**138/138** (4 phases + ext: scope narrowing, token TTL)
## Ground rules
@@ -79,7 +79,7 @@ lib/identity/api.sx ── (identity/login) (identity/grant?) (identity/revoke)
## Extensions (base roadmap complete; deepen the engine)
- [~] PKCE S256 method (RFC 7636 §4.2) — BLOCKED on erlang substrate (see Blockers)
- [ ] access-token TTL / `expires_in`tokens expire as a grant timeout, introspect honours it
- [x] access-token TTL / `expires_in`logical-clock expiry, introspect honours it
- [x] scope as a set + scope narrowing on refresh (RFC 6749 §6)
- [ ] client registry: public vs confidential clients, client authentication (RFC 6749 §2)
- [ ] client-credentials grant (RFC 6749 §4.4) and device grant (RFC 8628)
@@ -88,6 +88,13 @@ lib/identity/api.sx ── (identity/login) (identity/grant?) (identity/revoke)
- [ ] unify `api.sx` over oauth + membership + audit (one facade, audited login/consent)
## Progress log
- 2026-06-07 — access-token expiry (ext): logical clock in the token registry
(`advance`/`now`; no wall clock in substrate). Grants carry a Ttl; each
access token carries an Expires (Now-at-issue + Ttl, or infinity); introspect
returns inactive once `Now` reaches it. Refresh mints a fresh short-lived
access token (new Expires) — short access tokens, long refresh tokens. issue/4
+ issue_grant/4 default to infinity, so all prior tests unchanged. New
tests/expiry.sx (8). token loop/6. 130→138.
- 2026-06-07 — scope narrowing (ext): each access token now carries its own
EFFECTIVE scope (<= the grant's max). `refresh/3` requests a narrower scope;
the request must be a subset of the grant scope (RFC 6749 §6) else