Fixes from review of the device flow / introspection / DCR work:
Introspection over-disclosure (RFC 7662):
- Restrict introspection to authorized callers — the client a token was issued
to, or a resource server registered (resource_identifiers) to serve the token's
bound RFC 8707 audience. Unauthorized callers get {active:false}, disclosing
nothing, instead of any confidential client reading any token.
- Scope-gate disclosed claims: username only with the email scope, groups only
with the groups scope (mirrors userinfo). ADR 0005.
Tokens minted for revoked users:
- Re-check application.user_allowed?(user) at mint time in the device, refresh,
and authorization-code grants (covers app-active, user-active, group
membership). A user deactivated or removed from the allowed group between
approval and the token request is refused with access_denied. The refresh
check runs before rotation so a denied refresh has no side effects.
Device authorization hardening:
- Require confidential clients to authenticate, and require PKCE (code_challenge)
up front for clients that require it, so an intercepted device_code plus a
known public client_id cannot redeem tokens.
- Merge (not overwrite) the shared consent record on device approval.
Tests: new oidc_introspection_test and oidc_mint_authorization_test; existing
PKCE/claims tests updated to grant app access (they created ungrouped apps and
relied on the token endpoint not checking authorization). Full suite green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7cwhwDJp3MJJDoNPVE6zq
899 B
899 B
Architecture Decision Records
Short, dated records of non-obvious technical decisions in Clinch. They live in the repo (rather than a wiki) so they version with the code and travel with a checkout.
Each file is one decision. Newest decisions get the next number.
| # | Decision |
|---|---|
| 0001 | Access tokens are opaque (not JWT); resource servers use introspection |
| 0002 | CLI/agent auth uses the OAuth 2.0 Device Authorization Grant (RFC 8628) |
| 0003 | Dynamic Client Registration (RFC 7591), runtime-gated + default-deny |
| 0004 | Resource Indicators (RFC 8707) bind token audience; pass-through validation |
| 0005 | Introspection restricted to authorized callers + claim scope-gating |