Skip to content

feat(oauth): RFC 8693 token-exchange delegation (agentic on-behalf-of)#658

Merged
lakhansamani merged 5 commits into
mainfrom
feat/mai-delegation
Jul 8, 2026
Merged

feat(oauth): RFC 8693 token-exchange delegation (agentic on-behalf-of)#658
lakhansamani merged 5 commits into
mainfrom
feat/mai-delegation

Conversation

@lakhansamani

Copy link
Copy Markdown
Contributor

Summary

RFC 8693 token-exchange grant — the agentic delegation core. An authenticated service_account agent exchanges a user's subject_token (+ its own actor_token) for a resource-bound, attenuated access token carrying the nested act chain: "agent acting on behalf of user" (and, multi-hop, "sub-agent acting for parent agent").

Note: this PR's implementation was completed and tested by the coordinator after the builder's session limit; it is pending its security-engineer review before merge (all prior PRs were reviewed pre-merge).

What's here (grant_type=urn:ietf:params:oauth:grant-type:token-exchange)

  • Delegation-only (DC1/P3): actor_token is REQUIRED — subject-only (impersonation) is rejected invalid_request (impersonation is a separate admin-gated design).
  • Attenuation, fail-closed (DC2/H1): effective scope = subject_token.scope ∩ agent.AllowedScopes ∩ requested; empty ceiling = deny-all; monotonic non-widening (always intersects the subject token's own scope, so a re-exchange can only narrow).
  • Nested act (DC3, RFC 8693 §4.1): sub = the user; act = {sub: agent.client_id, act: <prior chain>}. act (and client_id) are reserved claims — a CustomAccessTokenScript cannot forge the delegation chain.
  • Act-chain depth cap (H1): hard limit on nesting; rejected beyond it.
  • Single resource (RFC 8707/DC4): exactly one resource required (0 or >1 rejected); the issued token's aud is that resource. Scoped to this grant only.
  • RFC 9068: issued token is typ: at+jwt with client_id; short TTL.
  • Discovery: token-exchange advertised in grant_types_supported.

Testing

  • Unit: intersectScopes non-widening + deny-all, actChainDepth nesting.
  • Integration: delegation-only rejection, exactly-one-resource, happy-path (token carries act.sub=agent, aud=resource, sub=user), attenuation (requesting a scope outside the agent's ceiling does not grant it).
  • go build/vet/gofmt/make lint-go clean; no codegen drift; full integration suite green (BC preserved).

Deferred (ponytail-noted)

Impersonation profile (subject-only, admin-gated); full delegation audit-chain fields across all providers (audit is minimal here); introspection/revocation of delegated tokens leans on the already-merged revocation-aware introspect.

…ssuance

WIP checkpoint: handler + delegation token issuance. Tests to follow.
…only, single-resource, nested act, attenuation)
… agent (review MEDIUM-1/2)

MEDIUM-1: distinguish machine vs user subject by login_method (not a failed user
lookup), so a transient DB error can't fail open past the RevokedTimestamp check.
MEDIUM-2: require the actor_token to be the authenticated agent's own token
(sub == client.ID), per RFC 8693 §1.1. Tests for both.
@lakhansamani
lakhansamani merged commit 4869b37 into main Jul 8, 2026
4 checks passed
lakhansamani added a commit that referenced this pull request Jul 22, 2026
…CP entries

Add exhaustive coverage of all PRs missed in the prior pass:

**Machine Identity (M2M) — PRs #648, #641-647, #652, #651, #654, #659, #655:**
- Unified OAuth Client registry with `kind` discriminator (interactive/service_account)
- client_credentials grant for service accounts (RFC 6749 §4.4)
- Secretless workload identity: RFC 7523 client_assertion, SPIFFE JWT-SVID, K8s TokenReview
- Registry-authoritative client authentication (introspect/revoke/discovery)
- Interactive client registry columns + reserved-client seed
- Shared client-auth resolver + grant-matrix hardening

**Agent Delegation (A2A) — PR #658:**
- RFC 8693 token-exchange for agentic on-behalf-of with nested act chains
- Scope attenuation (monotonic non-widening intersection)
- Hard depth cap on nesting; reserved claims prevent forging

**Multi-Tenant SSO/SCIM Foundations — PRs #653, #657, #660, #656:**
- Organization + user-org membership entities (CR1)
- Per-org OIDC SSO federation (Okta/Entra/Google as upstream IdPs)
- Per-org SAML 2.0 Service Provider SSO (XML-DSIG, replay detection, JIT)
- Per-org SCIM 2.0 user provisioning (+ 3 pre-existing storage bugs fixed)

**Authorization & Transports — PRs #625, #620:**
- OpenFGA ReBAC engine (replaces non-released bespoke FGA)
- Multi-protocol API: GraphQL + gRPC + REST + MCP
  - MCP: authorizer mcp CLI subcommand for claude mcp add
  - Single proto source of truth with buf STANDARD enforcement

**Dashboard & UI — PRs #662, #663, #605:**
- Admin pages: /identity/clients (with secret rotation), /identity/trusted-issuers
- Admin pages: /identity/organizations (with Members, SSO, SCIM tabs)
- UI migration: Chakra UI → shadcn/ui + Tailwind CSS (full type safety)

**Security & Compliance — PRs #604, #603, #606:**
- OIDC/OAuth2 spec compliance (RFC 6749 errors, auth_time, TTL, discovery)
- PKCE RFC-compliance (base64url padding tolerance, secret bypass prevention)
- Introspection auth bypass fix + backchannel SSRF hardening

**Bugfix — PR #664:**
- Expose public client_id in Client API type (distinct from surrogate id)

**README enhancements:**
- M2M: Add "Machine-to-machine (service-to-service) authentication" bullet
- A2A: Add "Agent-to-agent (A2A) delegation" bullet
- OIDC/OIDC: Clarify Authorizer is both IdP, RP/broker, and both for multi-tenant SSO
- Transports: Add MCP to "GraphQL, REST, gRPC" list; clarify admin API transports

Verification: All 32 PRs now have explicit CHANGELOG entries (consolidated where appropriate).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant