Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a14bfc-9643-7872-aa12-98326dcf25e7
124 lines
7.3 KiB
Markdown
124 lines
7.3 KiB
Markdown
# Optional online access-token status
|
|
|
|
Source proposal under KEY-WP-0042, driven by CUST-WP-0080 and existing
|
|
NK-WP-0048-T34/T42/T43 and RAPPS-WP-0016-T08/T09. Independent issuer/consumer
|
|
contract review and native admission remain required. Existing deployments are
|
|
unchanged. This extends the bounded issuer; it does not introduce a broker,
|
|
approval store, PDP, or a second application-local token registry.
|
|
|
|
The legacy profile authenticates self-contained JWTs until expiry. That does
|
|
not establish that an operation's initiating token is still unrevoked. The
|
|
optional profile adds issuer-owned current access-token status using
|
|
[RFC 7662](https://www.rfc-editor.org/rfc/rfc7662.html) introspection and
|
|
[RFC 7009](https://www.rfc-editor.org/rfc/rfc7009.html) revocation. It supports
|
|
access tokens only, without refresh tokens or token exchange.
|
|
|
|
## Enablement and lifecycle
|
|
|
|
Owner-admitted configuration opts in explicitly:
|
|
|
|
```yaml
|
|
tokenStatus:
|
|
enabled: true
|
|
maxEntries: 10000
|
|
```
|
|
|
|
The issuer must use HTTPS at its existing trusted ingress. The server's internal
|
|
HTTP listener and reverse-proxy topology are unchanged; direct HTTP exposure is
|
|
not admitted by an HTTPS issuer string. Omitted configuration keeps the existing
|
|
expiry-only token/UserInfo contract and advertises no new endpoints. Enabling
|
|
status registers `/introspect` and `/revoke`, advertises their implemented client
|
|
authentication methods, and connects the same store to issuance and UserInfo.
|
|
|
|
Human PKCE and service grants add a cryptographically random `jti` to each access
|
|
token. ID-token claims and existing assurance/tenant provenance remain unchanged.
|
|
Distinct grants in the same second have distinct bearer tokens: a new grant can
|
|
never remint a revoked token. A successful response is emitted only after the
|
|
token hash, expiry and current registration commitment have been recorded. No
|
|
bearer, client secret or identity/group snapshot is retained in the status store.
|
|
|
|
The store is bounded to the configured count (default 10000, maximum 1000000).
|
|
Live records and revocation tombstones are never evicted to admit another grant;
|
|
capacity exhaustion refuses issuance with a fixed 503. Expired entries are
|
|
collected when admitting a new token. Capacity and per-client ingress rate limits
|
|
need workload-representative admission: this is not a throughput/availability
|
|
claim or protection against an authorized client filling the bound.
|
|
|
|
This profile uses KeyCape's existing **single-instance topology**. Status is
|
|
process-local. Restart, deployment, rollback or store loss makes every earlier
|
|
token inactive at online endpoints, even if its JWT signature/expiry still
|
|
validates offline. Consumers must reauthenticate; there is no recovery replay
|
|
or token-state import that can resurrect revoked authority. Multiple replicas
|
|
are unsupported. Native admission must include this interruption and the
|
|
measured reauthentication/recovery procedure. A persisted/shared store is not
|
|
introduced here.
|
|
|
|
## Introspection and revocation
|
|
|
|
Both endpoints accept POST form bodies only, bound to 64 KiB; token values are
|
|
bound to 32 KiB. Query parameters, duplicate form or authentication fields,
|
|
unsupported content types and malformed authentication refuse without echoing
|
|
input. Responses use `Cache-Control: no-store` and `Pragma: no-cache`.
|
|
|
|
Introspection requires the existing registered confidential client's
|
|
`client_secret_basic` authentication. Only that client's own issued tokens can
|
|
be inspected. A separate resource audience is returned as `aud`, not confused
|
|
with the issuing `client_id`. Cross-client resource-server delegation needs a
|
|
separately reviewed authorization contract and is not implicitly granted by a
|
|
matching audience string. Public clients cannot enumerate token status.
|
|
|
|
An active response means the exact access token was issued in this process,
|
|
has not expired or been revoked, still matches its current complete registration,
|
|
and passes current issuer/signature/purpose validation. For humans, directory
|
|
lookup must succeed and the current account must be enabled and not suspended.
|
|
Status is checked again after directory lookup. Service subjects remain bound
|
|
to their current registration. Active output contains only standard access-token
|
|
metadata; inactive output contains only `active: false`. Unknown tokens, ID
|
|
tokens, altered tokens, another client's tokens and expired/revoked tokens all
|
|
return that same inactive response to an authenticated introspector.
|
|
|
|
Revocation authenticates confidential clients using the same method. A registered
|
|
public client may revoke its own token using `client_id` plus possession of that
|
|
bearer; public-client introspection remains unavailable. Revocation only affects
|
|
the exact token issued to that client. Unknown, other-client, expired and already
|
|
revoked tokens all produce the same empty 200. No token existence is disclosed.
|
|
Token-type hints do not bypass the actual access-token lookup. Removal or changes
|
|
to a registration invalidate online status; the commitment explicitly includes
|
|
the secret digest and internal token lifetime omitted from public Client JSON.
|
|
|
|
When enabled, actual UserInfo consults the same store before lookup and again
|
|
after it. Revocation therefore affects that existing endpoint immediately on its
|
|
next check. Ordinary login/logout and upstream Authelia sessions are distinct:
|
|
neither browser logout nor deleting a local cookie is represented as global
|
|
JWT revocation.
|
|
|
|
## Consumer contract and remaining acceptance
|
|
|
|
Online status establishes current access-token status, not permission
|
|
for an application resource or privileged effect. Consumers still independently
|
|
validate the actual signed token, admitted issuer/key/audience/type, subject,
|
|
tenant, principal type, assurance and freshness. The authenticated introspection
|
|
response must refer to that exact token/client. Obtain a new current response
|
|
before each protected operation; unavailable, malformed, inactive or ambiguous
|
|
responses refuse. A cached positive is not a current-session check.
|
|
|
|
Access Engine retains resource/action decisions, Approval Engine exact one-shot
|
|
approval, Warden admission and owner adapters execution. Bind their existing
|
|
descriptor, case, transaction and exact effect before dispatch. A separate new
|
|
operation/inverse token must be acquired and revoked on every terminal path;
|
|
renewed authentication cannot revive a consumed approval or replay a mutation.
|
|
This issuer capability alone implements none of those consumer bindings.
|
|
|
|
The producer-owned [current-token client](current-token-client.md) supplies the
|
|
shared Go/CLI transport and cryptographic/status join. Its private observations
|
|
retain this distinction: an inactive-for-client result is not an original
|
|
ownership or execution receipt. Native client/profile adoption remains open.
|
|
|
|
Native completion still requires independent issuer/profile review, exact
|
|
image/config/trust admission, bounded retained-token custody, real human/service
|
|
issuance, private transport, current-token/revocation integration in each owner,
|
|
all exit-path cleanup, restart/expiry/unavailable/refusal checks, ongoing
|
|
HTTP/API/Git/SSH authorization and audit evidence. Offline consumers which never
|
|
consult the endpoint retain their existing JWT validity; no estate-wide immediate
|
|
revocation claim follows from source implementation. Disabling the feature is
|
|
not an acceptable fallback for a consumer admitted under the online profile.
|