AARM governance requirement R10. Extends the R1–R9 agent-runtime governance framework (umbrella #216) with delegated identity / on-behalf-of authorization. Tracking issue in the #208 (R3) / #210 (R4b) / #215 (R9) convention. Implementing mechanisms are already scoped: #317 (interactive) and #318 (ID-JAG).
Requirement
A downstream tool call executes under the requesting user's delegated identity, not a shared service grant.
Where R9 (least-privilege credentials, #215) scopes what a tool may do, R10 scopes whose authority it acts under. Today an agent's remote-MCP OAuth is a single, process-global, deploy-time grant (storeKey = "mcp_" + name) — every end user shares one identity against the downstream app (Linear, Jira, GitHub…). For a multi-user deployed agent (Slack, or a UI → A2A) that violates least-privilege at the identity layer: there's no per-user authorization, no per-user attribution downstream, and a compromise of the shared grant is a compromise of every user's access.
R10 requires that per-user identity propagate to downstream tool calls — per-user, per-session, on-behalf-of — so the downstream system authorizes and audits the actual requesting user.
- Type: SHOULD (enterprise-grade; a proposed fourth SHOULD alongside R7/R8/R9).
- Status: proposed — not yet implemented.
Scope
R10 is the governance requirement; it is satisfied through one seam with a resolver behind it (design-tool-registry.md §18.2) — BearerToken(server, subject, session) — chosen per MCP server by method:. Forge never learns which resolver answered (that opacity is what lets the managed layer swap the backend):
| Resolver |
Layer |
Applicability |
| Forge-local — interactive OAuth, ephemeral per-session (#317) |
Forge (standalone-capable) |
any public OAuth MCP; universal |
Managed broker — vaulted 3LO now → ID-JAG later (initializ/aip/mcp-delegated-identity-broker.md; #318 Forge-side collapses to assertion-forward — the platform picks interactive vs ID-JAG, Forge never learns which) |
initializ / platform (holds the IdP trust relationship + token custody + consent delivery; §18.1 / §19) |
vaulted 3LO: real per-user delegation without EMA/XAA; ID-JAG: enterprise-federated end state |
Per §19 the Forge-facing axis is type: user | platform (the principal), not a method: — the platform decides interactive-vs-ID-JAG (opaque to Forge), and in managed mode the callback, consent delivery, and token custody are platform-side (the refresh token never touches the agent).
Both preserve per-user isolation and on-behalf-of identity, and share the identity-plumbing + session-store-interface defined in #317's P0. The broker resolver holds the credential and the enterprise trust relationship — it cannot live in the OSS agent framework (§18.1 test 3).
Fit within AARM (R1–R10)
- Sits next to R4b (STEP_UP / identity assurance of the caller to Forge) and R9 (least-privilege credentials for a tool). R10 completes the identity story: least-privilege identity — the caller's verified identity (which R4b/OIDC already establishes at the A2A edge) is propagated as the authority for the downstream action.
- Builds directly on existing primitives: the OIDC-verified
auth.Identity (raw assertion in hand at forge-core/auth/middleware.go:122), the DEFER park/resume engine (reused for the interactive gate), and the audit stream.
Audit events (planned)
Consistent with the R-series pattern (credential_issued / task_deferred / …):
mcp_auth_requested — a tool call needs a per-user token the session lacks; server, subject, strategy (interactive / id-jag).
mcp_auth_completed — token acquired for {subject, session, server}; strategy, wait_ms. Never carries token material or the raw assertion.
mcp_auth_denied — consent refused / IdP policy denied / grant rejected; server, subject, reason.
Acceptance criteria (requirement-level)
Related
Anchors
.claude/skills/forge.md §12.11 (R1–R10 map — R10 row added), forge-core/auth/{provider.go:46,middleware.go:122} (Identity + raw assertion), forge-core/mcp/oauth_flow.go (BearerToken seam), forge-cli/runtime/defer.go (park/resume reused by the Forge-local resolver's auth-required gate).
Requirement
A downstream tool call executes under the requesting user's delegated identity, not a shared service grant.
Where R9 (least-privilege credentials, #215) scopes what a tool may do, R10 scopes whose authority it acts under. Today an agent's remote-MCP OAuth is a single, process-global, deploy-time grant (
storeKey = "mcp_" + name) — every end user shares one identity against the downstream app (Linear, Jira, GitHub…). For a multi-user deployed agent (Slack, or a UI → A2A) that violates least-privilege at the identity layer: there's no per-user authorization, no per-user attribution downstream, and a compromise of the shared grant is a compromise of every user's access.R10 requires that per-user identity propagate to downstream tool calls — per-user, per-session, on-behalf-of — so the downstream system authorizes and audits the actual requesting user.
Scope
R10 is the governance requirement; it is satisfied through one seam with a resolver behind it (
design-tool-registry.md§18.2) —BearerToken(server, subject, session)— chosen per MCP server bymethod:. Forge never learns which resolver answered (that opacity is what lets the managed layer swap the backend):initializ/aip/mcp-delegated-identity-broker.md; #318 Forge-side collapses to assertion-forward — the platform picks interactive vs ID-JAG, Forge never learns which)Per §19 the Forge-facing axis is
type: user | platform(the principal), not amethod:— the platform decides interactive-vs-ID-JAG (opaque to Forge), and in managed mode the callback, consent delivery, and token custody are platform-side (the refresh token never touches the agent).Both preserve per-user isolation and on-behalf-of identity, and share the identity-plumbing + session-store-interface defined in #317's P0. The broker resolver holds the credential and the enterprise trust relationship — it cannot live in the OSS agent framework (§18.1 test 3).
Fit within AARM (R1–R10)
auth.Identity(raw assertion in hand atforge-core/auth/middleware.go:122), the DEFER park/resume engine (reused for the interactive gate), and the audit stream.Audit events (planned)
Consistent with the R-series pattern (
credential_issued/task_deferred/ …):mcp_auth_requested— a tool call needs a per-user token the session lacks;server,subject,strategy(interactive/id-jag).mcp_auth_completed— token acquired for{subject, session, server};strategy,wait_ms. Never carries token material or the raw assertion.mcp_auth_denied— consent refused / IdP policy denied / grant rejected;server,subject,reason.Acceptance criteria (requirement-level)
forge mcp login) remains available (opt-in per server) for single-identity/service use.docs/security/delegated-identity.md(R10) added to the governance set, cross-linked from the R-series map.Related
type: user— seam + assertion plumbing + standalone interactive resolver) · Agent-principal MCP OAuth resolver (type: platform) — unblocks headless-agent startup #324 (agent-principaltype: platform— the deployment-unblocking sibling) · MCP delegated identity: platform-side ID-JAG broker (Forge-side collapses to assertion-forward) #318 (Forge-side = assertion-forward; ID-JAG is a platform choice) ·initializ/aip/mcp-delegated-identity-broker.md(broker resolvers). Authority:design-tool-registry.md§18.Anchors
.claude/skills/forge.md §12.11(R1–R10 map — R10 row added),forge-core/auth/{provider.go:46,middleware.go:122}(Identity + raw assertion),forge-core/mcp/oauth_flow.go(BearerTokenseam),forge-cli/runtime/defer.go(park/resume reused by the Forge-local resolver's auth-required gate).