# Control Plane by Karl McGuinness > Thoughts on identity and security as a foundational control plane for modern software systems. Drawing on decades of experience building internet-scale identity platforms, the blog explores how authentication, authorization, access management, policy, and trust move upstream into shared infrastructure that governs who can act, what they can do, and how execution unfolds across systems. This file contains the full Markdown text of every published article. Canonical article URLs and individual Markdown URLs are listed before each document. --- # Authorization Denied Is No Longer Enough Canonical URL: https://notes.karlmcguinness.com/notes/authorization-denied-is-no-longer-enough/ Markdown URL: https://notes.karlmcguinness.com/notes/authorization-denied-is-no-longer-enough.md Most authorization systems still treat denial as the end of the interaction. ```json { "decision": false } ``` That model worked reasonably well in closed-world systems. Resources were known ahead of time. Applications were pre-integrated. Trust relationships were static. Permissions were provisioned before execution. Workflows were predictable enough that a denial usually meant the request was simply over. Modern systems increasingly do not work that way. Agents discover tools dynamically. Sub-agents delegate work downstream. Workflows cross trust boundaries. Resources appear at runtime. Missions evolve after they start. A request that is not authorized right now may still be legitimate if the right governance event occurs. In that environment, a deny is often not a full stop. It is the beginning of an escalation process. A support agent acting on behalf of an engineer may be authorized to investigate a tenant's billing issue, then discover that the cause sits in a restricted payment-provider log outside its current mandate. Reauthenticating the engineer does not answer the real question. The question is whether this mission should expand to include that tenant, that log, that operation, and that time window. A requestable denial lets the policy decision point (PDP) pause the workflow, bind the denial to the original evaluation, obtain a scoped governance decision, and reevaluate before access continues. That is the missing primitive: not an approval flow, but a requestable denial. The protocol move is a standardized way for a PDP to say: deny, but escalate. That realization is what led me to start working on what is now the [AuthZEN Access Request and Approval Profile](https://openid.github.io/authzen/authzen-access-request-approval-profile-1_0.html), an extension profile to the [OpenID AuthZEN Authorization API](https://openid.net/wg/authzen/) for representing requestable denials, submitting access requests, and reevaluating authorization after a governance workflow completes. But the more I worked on it, the more I realized this is not really about "access requests." It is about something larger: authorization escalation interoperability. That framing has now been validated externally. In May 2026, the OpenID AuthZEN Working Group adopted this work as a working group draft. Adoption is the working group signaling that requestable denials and authorization escalation are a real, in-charter gap worth standardizing, not a vendor-specific concern. The AuthZEN charter exists to make authorization interoperable across policy decision points and enforcement points through the Authorization API. Denial is part of that decision surface, so a standardized way to say "deny, but escalate" is a direct extension of what AuthZEN already standardizes rather than a departure from it. # Open-World Systems Break Static Authorization Traditional authorization systems assume the authority envelope can be determined upfront: which resources will be accessed, which operations will occur, which delegation paths will exist, and which trust domains will participate. That assumption breaks down quickly once agents enter the picture. As discussed in [OAuth for Open-World Ecosystems](/notes/oauth-for-open-world-ecosystems/), modern agents increasingly discover APIs dynamically, interact with previously unknown systems, expand workflows during execution, delegate tasks downstream, and cross organizational trust boundaries. An agent may begin with a valid authorization scope and still encounter new runtime conditions: a newly discovered mailbox, a downstream SaaS API, a stronger operation, a higher-risk dataset, a new tenant boundary, or a delegated execution path. The system now needs to answer a much harder question than "Is this token valid?" It must answer "Should authority continue under these newly discovered runtime conditions?" That is not authentication. It is runtime governance: deciding whether authority should change, not checking rights the agent already holds. # The Missing Layer Between Denial and Governance Most authorization systems today have a structural gap. A decision point can say a few things: allow, allow with obligations the enforcement point must satisfy, or deny. What it cannot say in a standard way is: > "Access is currently denied, but governance escalation is available." That last shape is a distinct decision, not a fuzzy one. A requestable denial is still a denial: the answer right now is no, and access does not proceed. It is not `indeterminate`, not "try again," and not "need more information." What separates it from a hard denial is a bound, explicit escalation path. A hard denial offers nothing to ask for. A requestable denial names where to ask and binds the request to the exact evaluation that was denied. That missing layer becomes important when authorization is no longer a single synchronous yes-or-no event. Agents, delegated execution, runtime discovery, mission expansion, and continuous governance all need a way to pause, ask for additional authority, and later return to the policy decision point with evidence that the governance event occurred. Today, that escalation is usually proprietary: custom approval APIs, ticketing integrations, internal workflow systems, ad hoc polling mechanisms, and vendor-specific governance models. In practice it is often less structured than that. An agent hits a wall, a human gets paged in Slack, someone glances at the request and clicks approve, and the agent is waved through by flipping a flag or widening an allowlist. The approval is a message in a channel. It is not bound to the denial, it is not re-checked when the agent actually proceeds, and it quietly becomes a standing exception nobody revisits. Every platform invents its own version of this, and the result is fragmented governance interoperability. The [AARM control plane](https://aarm.dev/spec) (Autonomous Action Runtime Management) intercepts every agent action before execution and resolves it to one of five decisions: allow, deny, modify, step-up, or defer. The last two are where a denial stops being the end of the story: step-up requires human approval before the action proceeds, and defer holds it pending more context. A requestable denial frames the other side of that boundary at the authorization layer: how the policy decision signals that escalation is available, how it is bound to the original evaluation, and how the result returns for reevaluation. AARM decides that an action should pause. This draft standardizes how that pause is expressed and resolved. # What the Draft Actually Does The goal of the [AuthZEN Access Request and Approval Profile](https://openid.github.io/authzen/authzen-access-request-approval-profile-1_0.html) is not to standardize workflow engines or approval systems. It standardizes the interoperability layer around authorization escalation. Walk it through with the support agent from earlier. It is investigating the billing issue and tries to read the restricted payment-provider log. The PDP returns a bare denial: ```json { "decision": false } ``` Nothing in that response separates "never" from "not yet." The profile turns it into a requestable denial that states the reason, names the escalation endpoint, and binds the request to this exact evaluation: ```json { "decision": false, "context": { "evaluation_id": "eval_01HX4Y2P8BQ4Y3F0V0K9D6Z7M1", "reason": "approval_required", "access_request": { "endpoint": "https://pdp.example.com/access/v1/requests", "template": "payment_log_access", "expires_in": 600, "request_context": "eyJhbGciOiJFUzI1NiIsImtpZCI6InBkcC0xIn0..." } } } ``` The authorization system is no longer returning only "No." It is returning "No, but governance escalation is available." The policy enforcement point (PEP) submits an access request to that `endpoint`, echoing `evaluation_id` and `request_context` so the request is tied back to the denial. It receives a Task Handle and polls until the task is terminal. When the engineer's manager approves the scoped expansion, the result carries an approval reference such as `apr_01J9F30RBX`. Then comes the step that matters. The PEP does not proceed on the strength of the approval. It issues a new AuthZEN evaluation for the same access, carrying the approval as an input: ```json { "subject": { "type": "agent", "id": "support-agent-7" }, "resource": { "type": "log", "id": "payment-provider/tenant-42" }, "action": { "name": "read" }, "context": { "approval": "apr_01J9F30RBX" } } ``` The PDP reevaluates against current policy, current subject state, and current risk, and only then returns: ```json { "decision": true } ``` If the mission had ended, the risk posture had shifted, or the approval had expired in the meantime, that same reevaluation returns `false` again. The approval bought a fresh decision, not a standing key. The base profile defines exactly one completion mode: `reevaluate`. The PDP remains authoritative end to end. An approval is not an access grant, and it is not a capability token: it does not travel forward as bearer authority to be replayed later. It is an input that current policy can choose to honor or reject at the moment of access. That is a deliberate defense against the time-of-check to time-of-use (TOCTOU) gap. The dominant failure in ticket-based access is exactly this gap: an approval granted at one moment becomes a standing entitlement still usable hours or days later, after the risk posture, the revocation state, or the mission that justified it has changed. Reevaluation forces the decision to be made again, against current state, every time the approval is presented. The obvious objection is cost. Reevaluation is another policy decision, but it runs once per escalation rather than once per request, on a PDP that is already in the path for the original deny. Paying for that fresh decision is the point. That changes denial from a terminal state into a governable lifecycle transition without changing what a denial means. # This Is Not Workflow Standardization One of the most important constraints of the draft is what it intentionally does not standardize. The draft does not define workflow engines, business process management (BPM) orchestration, approver routing, entitlement provisioning, governance policy languages, UI semantics, or human interaction models. Those remain implementation-specific. What the draft standardizes is narrower: - the shape of a requestable denial in an AuthZEN decision response - how an access request is submitted, with denial binding and idempotency - the Task Handle, lifecycle states, and polling semantics - terminal-state completion semantics, including reevaluation against current policy That separation matters. An enterprise may implement approvals using ServiceNow, SailPoint, Okta workflows, a custom governance system, a risk engine, an AI supervisor, a delegated approver, or a chain of policy evaluators. The interoperability problem exists independently of the workflow engine behind it. The draft keeps catalog references outside the form schema so the schema remains a pure description of data shape. It also does not define a UI rendering vocabulary or an agent protocol surface. The handoff is the surface area. Everything else stays local. # Why CIBA Is Not the Solution Whenever asynchronous approval flows come up, someone eventually asks, "Why not just use Client-Initiated Backchannel Authentication (CIBA)?" At first glance, [CIBA](https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html) appears close. Asynchronous interaction. Delayed completion. Polling semantics. Out-of-band approval. But CIBA solves a fundamentally different problem. CIBA is asynchronous authentication and consent for OAuth grant issuance. The successful terminal state is a token. The user proves they are present and consenting, and the authorization server issues a credential. Authorization escalation governance is different. The modern problem is often not "authenticate the user again." The harder problem is "should authority continue under newly discovered runtime conditions?" | Question | CIBA | Authorization escalation | | --- | --- | --- | | Missing input | Fresh user authentication or consent | Governance state | | Terminal result | Token issuance | Reevaluation input | | Authority source | Authorization server grant flow | PDP policy decision | | Best fit | Fresh login or grant consent | Runtime authority expansion | In this situation the agent already holds valid tokens and operates under an approved mission. Re-running an authentication flow changes none of that. The missing input is governance state: whether authority should expand now that boundaries, delegation paths, or risk have shifted. The draft intentionally avoids coupling approval directly to grant issuance. The lifecycle is: 1. authorization denied 2. escalation initiated against the denial binding 3. governance workflow executes 4. authorization context changes 5. authorization reevaluated under current policy That distinction preserves continuous evaluation, revocation, runtime policy, dynamic governance, and mission-bound authority. Approval alone does not create durable authority. The authorization system remains authoritative at evaluation time. That keeps the policy engine in charge of the access decision rather than the workflow engine. CIBA still has its place. When the missing input really is fresh user authentication or consent for a grant, CIBA is the right tool. When the missing input is governance state, it is not. # Sessions Are Not Missions, and Approvals Are Not Authority An approval answers whether a governance event occurred. A mission answers whether that event still justifies authority right now. The reevaluation step in the draft keeps those two questions separate. The approval is an input to policy. Policy decides whether the input still holds. This is the same shape as the argument in [Sessions Are Not Missions](/notes/sessions-are-not-missions/). Modern agent runtimes increasingly support durable execution: resumable sessions, background jobs, distributed orchestration, asynchronous continuation, and sub-agent execution. Runtime durability is not governance durability. A session answers where the agent can continue working. A mission answers why the agent is allowed to keep working. An agent may remain authenticated, maintain valid sessions, and preserve runtime continuity while still requiring governance escalation because new resources were discovered, stronger operations emerged, downstream delegation occurred, trust boundaries changed, or mission scope expanded. Authentication continuity is not governance continuity. An approval signed an hour ago is not a substitute for evaluating against current state. This is also why the Task Handle in the draft is opaque and portable. It survives PEP restart and can be passed between systems. A long-running agent that gets denied, escalates, hands work off to a sub-agent, and resumes on a different node should not need to rebuild the request from scratch. The handle is a runtime artifact for tracking the escalation. The mission, the approval, and the reevaluated decision are the governance artifacts that decide whether work continues. # Authorization Escalation as a Runtime Primitive The deeper pattern emerging across modern systems is this: authority increasingly outlives the moment that originally justified it. A static authorization decision made at one point in time becomes insufficient once execution continues for hours or days, resources are discovered dynamically, delegation chains evolve, risk posture changes, organizational state changes, or mission scope expands. This is the same gap [From Passports to Power of Attorney](/notes/from-passports-to-power-of-attorney/) names from the credential side and [Governing the Stay, Not Just the Entry](/notes/governing-the-stay-not-just-the-entry/) names from the control-plane side. The badge is not the work order. The token is not the mandate. The session is not the mission. A standardized escalation handoff lets each of those layers stay honest. The PDP can say "deny, but escalate" without inventing its own approval API. The mandate service ([Power of Attorney series](/series/you-dont-give-agents-credentials-you-grant-them-power-of-attorney/)) can be the system of record for whether the mission still holds. The workflow engine can remain the system of record for how an approval was reached. The agent runtime can carry a Task Handle without becoming the source of truth for authority. What this layer needs to be: - **A protocol surface, not a workflow language.** Approval routing, escalation policy, and approver selection stay implementation-specific. - **Policy-authoritative on completion.** The PDP reevaluates against current state. An approval is an input, not a verdict. - **Lifecycle-explicit.** Pending, approved, denied, expired, cancelled, failed, partial. Unknown states are not approval. - **Bindable to the denial.** Either a verifiable evaluation identifier or a signed request context, never a floating approval against an unbound denial. - **Portable.** Handles survive runtime churn and cross process boundaries, because the agents that need this most are the ones that do not stay on one node. None of those properties are workflow features. They are interoperability properties. # What This Is Converging Toward The traditional model: ```json { "decision": false } ``` is becoming insufficient for agents, runtime delegation, dynamic resource discovery, mission expansion, and continuous governance. The future increasingly looks more like: ```json { "decision": false, "context": { "reason": "approval_required", "access_request": { "endpoint": "...", "template": "..." } } } ``` followed later by a reevaluation against the resulting approval. Current policy decides whether the approval still holds. That is the direction this work is converging toward: not "access requests" as a workflow primitive, and not "approval flows" as a vendor feature, but a standardized interoperability layer for authorization escalation, runtime governance, and mission continuity. The protocol surface is small on purpose. The hard work of deciding who approves what, under which policy, against which mission, with which evidence, stays exactly where it belongs: not in the authorization API, not in the workflow engine, but in the layer that owns mission authority. This is a working group draft for a reason. The edges still need to be battle-tested. Whether you are building agent runtimes, high-throughput API gateways, or access-request and approval products, I want to know where this handoff breaks down. Join the conversation in the [OpenID AuthZEN Working Group](https://openid.net/wg/authzen/), or open an issue on [GitHub](https://github.com/openid/authzen). Denial is no longer always the end of the interaction. It is becoming a state in a governable lifecycle. The protocol needs to recognize that, and only that. The rest of the stack can then stop reinventing it. --- # SAML at the Post-Quantum Crossroads Canonical URL: https://notes.karlmcguinness.com/notes/saml-at-the-post-quantum-crossroads/ Markdown URL: https://notes.karlmcguinness.com/notes/saml-at-the-post-quantum-crossroads.md The enterprise technology industry has been here before. SHA-1 certificate deprecation and TLS 1.0/1.1 removal were both deferred across the industry until browser vendors coordinated hard deadlines that made non-compliance a user-visible problem rather than a future risk. The organizations that treated those transitions as somebody else's future problem were the ones scrambling when the deadline arrived. The technology to migrate had existed for years. The pressure to act had not. What distinguished the transitions that went well from the ones that did not was whether the migration path was built into the technology itself. SHA-2 and SHA-1 could coexist during transition because PKI clients and certificate chains could tolerate mixed algorithm use while issuers, subscribers, and relying parties moved on different schedules. The transitions that succeeded with the least disruption were the ones where parallel operation was possible: old trust and new trust recognized simultaneously, with a defined handoff point rather than a hard cutover. SAML is approaching a version of that deadline, and the migration path does not yet exist in standardized form. A SaaS vendor may have hundreds of enterprise SAML customers: some using persistent NameIDs, some using email addresses, some using custom attributes, some depending on IdP-initiated launch, and many relying on undocumented group-to-role mappings. The vendor can add OIDC for new customers, but it cannot simply switch existing tenants without risking duplicate accounts, broken administrator access, and failed audits. That is the core problem: identity contract continuity. The hard part is not adding another login protocol. It is proving that the new OIDC relationship is the successor to the old SAML federation without changing the subject, audience, attribute, or authorization semantics the application already depends on. I have been working on a draft specification, the [OpenID Connect Migration Profile for SAML 2.0 Service Providers](https://mcguinness.github.io/connect-saml-profiles/draft-connect-saml-migration-profile.html), to address that directly. It is now part of a broader set of [interoperability profiles](https://github.com/mcguinness/connect-saml-profiles) for SAML and OpenID Connect coexistence, because migration in practice is never a single hard cutover. This post explains why the problem is harder than it looks and where the specifications need review from people who will actually have to execute the migration. The pressure comes from two directions that compound each other. XML Signature complexity has produced a sustained vulnerability class across SAML implementations, and most of the library stacks enterprises depend on are in various states of deferred maintenance. Post-quantum migration now adds a hard coordination deadline on top of that deferred debt. The organizations with the most SAML maintenance debt are the least equipped to execute a coordinated algorithm migration when the timeline becomes binding. That is not a coincidence. It is the same organizations that treated SAML as a procurement checkbox in the early 2010s who are now running aging library stacks with limited institutional knowledge of how to change them safely. Post-quantum migration does not create new migration obligations for SAML estates. It converts deferred maintenance into a hard deadline. OpenID Connect is not new. The OpenID Foundation [ratified the core specification in February 2014](https://openid.net/2014/02/). In October 2024, [nine OpenID Connect specifications were published as ISO/IEC international standards](https://openid.net/10-years-on-openidconnect-published-as-iso-spec/). The protocol is mature, widely deployed, and built on the OAuth 2.0 stack with more than a decade of enterprise deployment behind it. And yet SAML is still the enterprise default for SSO. # Why SAML Still Wins SAML remains dominant because the enterprise buying and operating model was built around it. Many RFPs still ask for SAML by name. Compliance teams know how to evaluate it. SaaS vendors know that if they do not support SAML, they may lose enterprise deals before a security architect ever reads their OIDC documentation. Identity teams have years of runbooks for exchanging metadata, rotating certificates, mapping attributes, testing IdP-initiated and SP-initiated login, and recovering from lockouts. For browser-based workforce SSO, SAML is often boring in the best sense: it is well understood, broadly supported, and easy for enterprise administrators to reason about. There is also a security intuition behind SAML that should not be dismissed. In a typical SAML deployment, the service provider pins trust to an IdP signing certificate or metadata document controlled by the customer. The customer can often bring their own PKI, rotate keys through a known administrative process, and reason about the blast radius of a compromised signing key in a way that feels concrete. OIDC, by contrast, is often perceived as more dynamic: the relying party discovers issuer metadata, follows a JWKS URL, and validates JWTs against keys published by the issuer. That model is mature and secure when implemented correctly, but a certificate uploaded into an admin console looks like a boundary. A URL that returns keys looks like a dependency. SAML has not failed. The environment around it has. But enterprise familiarity is not the same thing as long-term safety. The question is no longer whether SAML can keep working. It is whether SAML should keep absorbing new enterprise identity requirements that its trust model was never designed to carry. # The Assertion Ceiling SAML is a presentation layer for authentication. The assertion is the relationship. When a user logs in, the IdP constructs an assertion encoding what it knows about that user at that moment: a subject identifier, authentication context, and whatever attributes the integration was configured to include. The service provider validates it, maps the claims into a local session, and moves on. That is the protocol boundary. There is no ongoing connection, no shared API surface, and no standardized way for the service provider to query the IdP after the assertion is consumed. That boundary matters because the enterprise identity graph is larger and more dynamic than any assertion can carry. The organizational context that enterprise applications actually need (reporting structures, cost center assignments, entitlements across systems, device posture, group memberships that change as people move roles) cannot be practically embedded in a login-time assertion. Either the IdP preloads every attribute every application might ever need, or each application maintains its own copy through a separate provisioning channel, or it works with incomplete information about the user it just authenticated. An application that needs to verify current entitlements before authorizing a sensitive operation cannot query the IdP through SAML. A service that wants to publish an access event back to the identity system has no standard SAML channel to do so. A policy engine that wants to evaluate real-time identity context at authorization time cannot call the IdP the way it would call any other API. Each of these capabilities requires a separate integration with a proprietary vendor API, a custom side channel, or nothing happens. OIDC changes this because the service provider is an OAuth client. The IdP is an authorization server that can issue scoped, audience-bound, revocable access tokens the SP uses to call APIs on the user's behalf when those APIs and scopes are part of the enterprise profile: richer profile queries, organizational data, entitlement lookups, event subscriptions. The trust model is delegation-shaped, not assertion-shaped. SAML authenticates the user into the application. OIDC can also authorize the application to call identity APIs after login. Where SAML makes a one-time statement that the SP consumes and discards, OAuth tokens explicitly bind what the SP is allowed to do, against which APIs, for how long, and on whose behalf, with revocation as a first-class operation rather than an out-of-band hope. The authentication exchange can become an entry point, not a ceiling. This is part of what IPSIE is defining: not just how OIDC handles SSO, but how the IdP's API surface covers entitlements, lifecycle events, risk signal sharing, and the enterprise identity relationships that cannot live in an assertion. SAML provides no equivalent foundation. | Dimension | SAML | Enterprise OIDC profile | | --- | --- | --- | | Primary artifact | Login-time assertion | ID token plus scoped access tokens | | Trust shape | Assertion consumption | Delegated API access | | Post-login identity context | Out of band | Profiled API surface | | Key discovery and rotation | Metadata and certificate distribution | Issuer metadata and JWKS | | Migration risk | Subject and attribute continuity | Requires explicit succession semantics | # The XML Problem The issue is not that SAML is old. Old protocols can be excellent. The issue is the surface area created by XML and XML Signature. [SAML 2.0](https://www.oasis-open.org/standard/saml/) is an OASIS standard for XML-encoded identity assertions, and its security depends heavily on correct XML canonicalization, reference resolution, ID handling, signature validation, and claim extraction. The relying party must not merely check that some signature is valid. It must ensure the signed element is the exact element whose claims are processed. That distinction sounds obvious until you look at the history of XML Signature wrapping and SAML validation bugs. XML Signature signs specific nodes within a document, not the document as a whole. A wrapping attack inserts a second, unsigned copy of the assertion outside the signed scope. If the validator and the application disagree about which element to read, the signature check passes against the legitimate element while the application consumes claims from the attacker-controlled copy. The signed element is valid. The claims the application acts on are not from it. The classic 2012 USENIX paper ["On Breaking SAML: Be Whoever You Want to Be"](https://www.usenix.org/conference/usenixsecurity12/technical-sessions/presentation/somorovsky) analyzed 14 SAML frameworks and found critical XML Signature wrapping vulnerabilities in 11 of them. In 2018, [Duo Labs disclosed SAML vulnerabilities affecting multiple implementations](https://duo.com/blog/duo-finds-saml-vulnerabilities-affecting-multiple-implementations), including OneLogin libraries, OmniAuth-SAML, Shibboleth, and Duo Network Gateway. The mechanics differed across disclosures, but the security failure was the same: the implementation accepted one signed identity context while the application acted on another, allowing an attacker with a legitimate account in the same federation to authenticate as another user, including an administrator. The pattern did not stop with the 2018 disclosures. In September 2024, a maximum-severity authentication bypass (CVE-2024-45409, CVSS 10.0) was disclosed in ruby-saml, a widely deployed library used by GitLab and other applications. The root cause was the same: the library failed to enforce that the elements it extracted claims from were covered by the signature it validated. An attacker with access to any SAML document legitimately signed by the IdP could forge a SAML response and authenticate as any user, including administrators, without that user's credentials. Within weeks, working exploit code was published, turning a structural flaw into a point-and-click bypass. Additional critical ruby-saml disclosures followed in 2025, including [CVE-2025-25291](https://rubysec.com/advisories/CVE-2025-25291/) and [CVE-2025-25292](https://rubysec.com/advisories/CVE-2025-25292/), where parser differentials again allowed signature wrapping and authentication bypass. The twelve-year span from the original USENIX paper to the present has not resolved the structural problem. It has confirmed it. This vulnerability record points to a structural supply-chain problem more serious than any individual disclosure. Most SaaS SAML implementations were built on open-source toolkits assembled during the early-to-mid 2010s, when enterprise SAML support was a procurement gate and implementation speed mattered more than long-term maintenance posture. The dependency graph runs from the SaaS product down through a SAML library, through an XML processing library, and into platform XML infrastructure. Each layer has its own release cadence, its own CVE history, and its own patch requirements. The maintenance dynamic compounds the risk. SAML support is typically treated as a procurement feature: once the enterprise requirement is satisfied, the implementation joins the maintenance queue. In many organizations, the engineers who built the original SAML stack are no longer at the company. The XMLDSIG expertise required to safely evaluate a new vulnerability disclosure is not retained. A new CVE in a SAML library triggers a dependency update process, not a security design review, because the institutional context for a design review no longer exists. This is what makes the XML problem structurally different from a standard software vulnerability. It is not one flaw in one implementation that can be patched. It is a property of XMLDSIG that creates a high-complexity validation problem for every implementation, reproduced across Java, Python, Ruby, PHP, and .NET, across different teams, in different decades, sustained indefinitely by a supply chain that treats SAML as a procurement checkbox rather than a security subsystem. # Post-Quantum Raises the Stakes Post-quantum cryptography changes the SAML conversation because authentication signatures are squarely in the migration scope. The question is not just whether new algorithms can be added. It is whether the existing SAML estate can move to them before deferred maintenance becomes a compliance and availability problem. NIST finalized its first post-quantum signature standards in August 2024: [FIPS 204 (ML-DSA)](https://csrc.nist.gov/pubs/fips/204/final) and [FIPS 205 (SLH-DSA)](https://csrc.nist.gov/pubs/fips/205/final). NIST's draft transition guidance, [IR 8547](https://csrc.nist.gov/pubs/ir/8547/ipd), identifies RSA, ECDSA, and EdDSA as quantum-vulnerable signature standards and sketches a migration path away from them. Cloudflare has published a [2029 target for full post-quantum security](https://blog.cloudflare.com/post-quantum-roadmap/) across its infrastructure, including authentication. The direction is not speculative. The question for enterprise SAML estates is not whether authentication signatures need to move, but whether the SAML implementation substrate can execute that migration. Federal agencies are already expected to inventory cryptographic dependencies. Enterprise identity platform procurement and migration cycles can run years for anything touching thousands of integrations. If algorithm deprecation requirements harden around 2030, the window to begin planning is already open. For organizations subject to federal compliance requirements like CMMC and FedRAMP, the pressure is more concrete: if those requirements arrive before the SAML implementation stack in production can support ML-DSA or SLH-DSA, the enterprise SSO infrastructure chosen for its auditability becomes a compliance liability. Migrating SAML to post-quantum signatures means updating the signing algorithm in the IdP, distributing new public key material to every service provider's trust configuration, updating the SAML library to implement the new algorithm, updating the XML Signature algorithm identifiers used in assertions, and ensuring every validation path in every relying party correctly processes the new key type and signature format. For large academic and research federations like InCommon in North America and eduGAIN across Europe, the coordination scope is far larger. InCommon alone connects more than 1,000 participating organizations through a centralized metadata authority, and eduGAIN federates thousands more across Europe. The centralized metadata model that makes SAML federation manageable in normal operations becomes an amplification factor for migration risk when a disruptive algorithm transition is required. OIDC and OAuth sit on top of the JOSE family of standards (JWS, JWE, JWT, JWK, JWA), and the [IANA JOSE algorithm registry](https://www.iana.org/assignments/jose/jose.xhtml) is the extensibility point that lets new signature algorithms be added without protocol changes. A new signature algorithm needs a JWA identifier, a JWK representation, JWKS publication, and updated validation logic. The ecosystem plumbing for discovery, key rotation, JWKS caching, and metadata is already built to accommodate algorithm transitions. That extensibility has now produced a concrete post-quantum standard. [RFC 9964](https://www.rfc-editor.org/rfc/rfc9964.html), published on the IETF Standards Track in May 2026, specifies ML-DSA (FIPS 204) for JOSE and COSE: algorithm identifiers, JWK key representations, signature encoding, and the ML-DSA-44, ML-DSA-65, and ML-DSA-87 parameter variants needed for interoperable implementation. An OIDC issuer can now publish ML-DSA keys at its JWKS endpoint against a published standard rather than a vendor extension, and any conformant relying party can validate them. No equivalent standards-track work exists for XMLDSIG. The XML Signature algorithm registry has no published post-quantum identifiers, no profile defining how ML-DSA or SLH-DSA keys appear in SAML metadata, and no agreed encoding for those signatures on the wire. Enterprise SAML estates needing post-quantum signatures will be waiting on standards work that has not started, while OIDC deployments are waiting on implementation of a standard that already exists. A post-quantum XMLDSIG profile, whenever it arrives, would not escape the deeper problem. As noted above, XML Signature signs specific nodes rather than the document as a whole, and that node-versus-consumed-element gap is the wrapping class itself. JWS signs the entire token as a single unit, so that class of attack structurally cannot arise. Swapping in ML-DSA changes the signing algorithm; it does not change which bytes are protected. A post-quantum SAML would inherit the same validation surface that produced twelve years of wrapping disclosures, while JWS never had it. The post-quantum migration for OIDC is not free. RFC 9964 is a target to build to, not a finished deployment. But there is a material difference between an ecosystem where the standard exists and implementations need to catch up, and one where the standards work itself has not yet started. The same SaaS organizations that have not kept their SAML library dependency current for routine CVE patches will face a more complex migration: new algorithm support requiring new library versions, new key management, new certificate infrastructure, and coordination with every customer integration. Unlike a routine CVE patch, there is no option to defer indefinitely. Organizations that deferred longest carry the most concentrated coordination risk when migration timelines become binding. # Why Migration Is Hard Saying new SSO integrations should use OIDC is the easy part. Migrating the existing estate is not. Most enterprise applications in production already have established SAML federations. Those integrations are tied to user identifiers, group mappings, role assignments, SCIM provisioning, app sessions, break-glass processes, help desk runbooks, audit expectations, and contractual support language. Changing the SSO protocol is not a refactor. It is an operational event with outage risk. From the customer's perspective, the upside often looks small. If the migration goes perfectly, users may see one extra redirect or no visible change at all. If it goes badly, users are locked out, the help desk floods, executives cannot access critical apps, and the identity team owns the incident. This is why SAML persists even when everyone in the room agrees that OIDC is the modern direction. The migration cost is immediate and local. The security benefit is long-term and systemic. The person approving the migration carries the outage risk while the benefit accrues to a future operating model. Vendors keep implementing SAML because customers require it. Customers keep requiring SAML because vendors support it and their existing estate runs on it. New vendors that would prefer to implement OIDC still worry that excluding SAML will shrink their enterprise TAM. If they expect to support SAML eventually, they implement it early and add yet another SAML stack to the world. A single enterprise SAML integration may depend on a NameID format, custom attribute mappings, group-to-role rules, SCIM provisioning assumptions, certificate rotation procedures, IdP-initiated launch behavior, session timeout expectations, and help desk recovery paths. None of those show up in a simple protocol comparison chart. Every one can break during migration. The missing ingredient is not a better argument for OIDC. It is a migration path that is explicit, standardized, and low-risk enough that the people approving migrations can trust it, and that vendors can build to without inventing a bespoke solution for every customer. That is the gap the migration profile is trying to standardize: not a new login protocol, but a way to prove that an OIDC client is the successor to an existing SAML service provider relationship. # Two Things Would Help ## A Secure Enterprise OIDC Profile The first missing piece is a clearer definition of secure enterprise SSO for OIDC. The OpenID Foundation's [IPSIE Working Group](https://openid.net/wg/ipsie/) is working toward that: profiles for enterprise identity covering single sign-on, user lifecycle management (SCIM), entitlements, risk signal sharing (via the [Shared Signals Framework](https://openid.net/specs/openid-sharedsignals-framework-1_0.html) and [CAEP](https://openid.net/specs/openid-caep-1_0.html)), logout, and token revocation, with a charter that explicitly prioritizes secure defaults. That work matters because "supports OIDC" is not a security claim. OIDC has its own failure modes: issuer mix-up, redirect URI mistakes, weak `state` or `nonce` handling, unsafe account linking, tenant-claim misuse, and JWKS caching errors. OAuth's recent evolution is the closest precedent. [RFC 9700](https://datatracker.ietf.org/doc/html/rfc9700) (BCP 240) updates the OAuth 2.0 security baseline based on more than a decade of deployment experience, and [OAuth 2.1](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/) is consolidating those lessons into the core authorization framework by requiring PKCE for all clients, removing weaker grant types like the implicit grant and Resource Owner Password Credentials, and requiring exact redirect URI matching. The [FAPI 2.0 Security Profile](https://openid.net/specs/fapi-2_0-security-02.html) goes further, demonstrating that a hardened OIDC profile can be defined and conformance-tested at scale, originally for high-assurance financial APIs. IPSIE applies the same approach to enterprise SSO. Enterprise buyers need an equivalent baseline for OIDC SSO. Vendors need a target they can build to and demonstrate conformance against. Optionality is where interoperability and security both go to die. ## A Real SAML-to-OIDC Migration Story The second missing piece is a standardized migration path that preserves identity contract continuity. It is not enough to tell customers to create a new OIDC application and cut over. Migration has to preserve the identity contract the application already depends on. That means mapping SAML issuers, NameIDs, attributes, groups, and tenant identifiers into OIDC issuer and claim semantics without breaking subject resolution. It means supporting staged rollout, dual configuration, telemetry, rollback, and test modes. At minimum, a credible migration story needs to cover: - Preserve subject continuity across the protocol switch, accounting for both SAML NameID format variation (persistent, transient, email, X.509 SubjectName) and OIDC's pairwise versus public `sub` semantics, so the application does not accidentally create a second account for the same user. - Establish the OIDC trust anchors as successors to the existing SAML relationship, with defined bindings from SAML IdP EntityID to OAuth issuer and from SAML SP EntityID to OAuth client identifier, so the new trust relationship is provably the continuation of the existing one rather than a parallel federation. - Map SAML AudienceRestriction (typically the SP EntityID URI) onto OIDC `aud` (typically a `client_id`) without weakening audience validation in either direction. - Map SAML attributes, groups, and tenant identifiers into OIDC claims without changing application authorization semantics. - Define the scope of the migration with respect to the OAuth token model: whether the profile covers ID-token-only authentication, or also access and refresh tokens with their independent lifetimes, scopes, and revocation semantics. - Support parallel validation during rollout so administrators can test the new OIDC path before disabling SAML. - Give the application a way to distinguish an intentional protocol migration from accidental or malicious account linking. The industry does not yet have a standard answer to any of these requirements. Each vendor that has attempted SAML-to-OIDC migration has invented its own approach, with its own subject-mapping logic, its own account-linking semantics, and its own untested edge cases. That bespoke improvisation is what makes migration feel more dangerous than it should be, and it is why some migrations that appeared to succeed produced silent account-linking errors that only surfaced later. Consider a user whose SAML identity was a persistent, opaque NameID, but whose new OIDC integration resolves identity from the `email` claim. The cutover does not throw an error. It silently creates a second account, while the user's group memberships, entitlements, license assignment, and audit history stay attached to the original. The user logs in, sees an empty workspace, and files a ticket. Nobody connects it to the migration. The failure mode that costs the most is not the one that pages the on-call engineer at cutover. It is the one that surfaces months later as two accounts for one person in an access review, or as orphaned entitlements a compliance audit cannot explain. The [migration profile](https://mcguinness.github.io/connect-saml-profiles/draft-connect-saml-migration-profile.html) is built for exactly this. It uses RFC 8693 Token Exchange and SAML assertion introspection to bind new OAuth clients to existing SAML SP relationships through registered `saml_sp_entity_id` and `saml_idp_entity_id` metadata, so the trust anchor, audience, and subject derivation carry forward from the original federation rather than being reinvented per vendor. A three-way binding among the authenticated client, the registered SP EntityID, and the assertion audience is what lets applications verify a migration is intentional rather than an accidental, or malicious, account-linking event. No SAML estate moves all at once, so the migration profile is now one of three [interoperability profiles](https://github.com/mcguinness/connect-saml-profiles) that let old trust and new trust run side by side. Each covers one direction of the transition, and together they describe a staged journey rather than a single switch: | Profile | Precondition | Postcondition | Outcome and value | | --- | --- | --- | --- | | **IdP-backed OP** | SAML IdP is the authoritative authentication authority, with no OIDC entry point | An OpenID Provider sits in front of the SAML IdP and delegates authentication upstream to it | New OIDC apps and relying parties onboard immediately while SAML stays authoritative; OIDC gets a front door with nothing migrated yet, which makes the rest low-risk | | **Migration** | An existing SAML SP federates with its own NameID, attributes, and trust configuration | The SP is now an OIDC relying party of the OP, bound to its former SAML SP and IdP entity IDs | Each SP moves on its own schedule with subject and audience continuity preserved; no duplicate accounts and no estate-wide cutover | | **Bridge** | The OP is authoritative, but some SPs cannot migrate (vendor end-of-life, frozen or contractual integrations) | The OP presents a SAML IdP facade, deriving SP-specific NameIDs and attribute release from OIDC claims | Legacy SAML SPs keep working unchanged; no SP is stranded and no forced simultaneous cutover | The unit of migration is the integration, not the company. Each SP moves when it is ready, and nothing in front of it has to wait. The phases overlap rather than gate each other, which is the point: old trust and new trust recognized simultaneously, with a defined handoff point rather than a hard cutover, the same parallel operation the SHA-1 transition relied on. The specifications are early. They need review from the identity providers, application vendors, and enterprise architects who know where the real edge cases are. # What to Do Now **Enterprise buyers** should stop making SAML the default requirement for new SSO. Treat SAML as a legacy compatibility protocol, while new enterprise SSO requirements should require secure OIDC support with documented SAML-to-OIDC migration semantics. Concretely, replace language like: > *The solution must support SAML 2.0 for enterprise SSO.* with: > *The solution must support SAML 2.0 for enterprise SSO, or an enterprise OIDC profile with documented migration semantics that preserve subject continuity for accounts currently authenticating via SAML. Vendors must demonstrate how existing SAML integrations can be migrated to OIDC without requiring account re-linking or high-risk cutovers.* The more important question is not whether a vendor supports both protocols, but how they handle migration: does their OIDC implementation preserve subject continuity for accounts that currently authenticate via SAML, or does it require a high-risk cutover? That question, asked early in procurement, changes what vendors prioritize. Buyers should also inventory existing SAML integrations for the ones most likely to become blockers: custom NameID formats, fragile attribute mappings, manual certificate rotation, and undocumented group and role mappings are the integrations that make migration expensive. **Application vendors** should stop treating SAML as a checkbox dependency. Prefer OIDC for new enterprise SSO, while treating existing SAML support as legacy-critical infrastructure that requires real maintenance. That means dependency tracking, XMLDSIG test coverage, signature-wrapping regression tests, and certificate-rotation hygiene. The test to apply: can you migrate a SAML customer to OIDC without creating a second account or disrupting their group and role assignments? If the answer is no, the OIDC implementation is not production-ready for enterprise migration. **Identity providers and standards groups** should make migration conformance-testable. IPSIE can define the secure enterprise OIDC baseline. Migration profiles can define how existing SAML relationships move without account-linking ambiguity or high-risk cutovers. Conformance tests can turn those expectations into something verifiable rather than aspirational. The organizations that start now will have chosen their timeline. The ones that wait will have it chosen for them, by the next signature-validation disclosure, a supply-chain failure in a SAML library they forgot they depended on, or a post-quantum deprecation deadline that arrives before their XMLDSIG stack is ready to move. The destination is not exotic. It is enterprise SSO on a hardened OIDC profile, with post-quantum signatures published against a standard that already exists, reached by a migration path that carries existing SAML relationships forward without orphaning a single account. The technology to get there is arriving. The only open question is whether the planning starts before the deadline does. # Get Involved ## SAML 2.0 and OpenID Connect Interoperability Profiles The [interoperability profiles](https://github.com/mcguinness/connect-saml-profiles) are early-stage drafts, not finished standards. They cover three complementary directions: the [Migration profile](https://mcguinness.github.io/connect-saml-profiles/draft-connect-saml-migration-profile.html) (SAML SP to OIDC), the [Bridge profile](https://mcguinness.github.io/connect-saml-profiles/draft-connect-saml-bridge-profile.html) (an OP serving un-migrated SAML SPs through an IdP facade), and the [IdP-backed OP profile](https://mcguinness.github.io/connect-saml-profiles/draft-connect-saml-idp-profile.html) (an OP delegating authentication to an upstream SAML IdP). The goal is to get the problem definition and requirements in front of people who will actually have to execute this migration, and find out where the approach is wrong before it goes further. If you work on enterprise identity, one of these questions is probably worth your time: - **Identity providers**: Does this profile describe what your migration tooling already does? Where does it conflict with your implementation, and where are the gaps? - **SaaS application vendors**: If you support both SAML and OIDC today, does this profile give you a workable path to migrate existing SAML customers without a high-risk cutover? What is missing? - **Enterprise architects**: If you are planning or deferring a SAML-to-OIDC migration, does this profile address the identity contract requirements that make migration feel risky? - **Standards reviewers**: The subject-mapping semantics and trust relationship model should be challenged. If the approach does not hold for your deployment scenario, that feedback is exactly what shapes whether this becomes a useful standard. Feedback and discussion are open on [GitHub](https://github.com/mcguinness/connect-saml-profiles). ## IPSIE Working Group The [IPSIE Working Group](https://openid.net/wg/ipsie/) at the OpenID Foundation is defining what secure enterprise OIDC actually means in practice: profiles for SSO, user lifecycle management, entitlements, risk signal sharing, logout, and token revocation. That work is only as good as the enterprise requirements it is built against. If you are an enterprise buyer with real deployment constraints, an identity provider with implementation experience, or a SaaS vendor who has navigated the gap between "supports OIDC" and "secure for enterprise," the working group needs your input. The specifications produced there will become the baseline that procurement language can require and vendors can build to. Getting the requirements right now is easier than correcting them after conformance tests exist. Information on participating is available at [openid.net/wg/ipsie](https://openid.net/wg/ipsie/). --- # The Agent Provider Is the IdP: A Standards Reading of WorkOS auth.md Canonical URL: https://notes.karlmcguinness.com/notes/agent-provider-is-the-idp-standards-reading-of-workos-auth-md/ Markdown URL: https://notes.karlmcguinness.com/notes/agent-provider-is-the-idp-standards-reading-of-workos-auth-md.md When WorkOS published [auth.md](https://workos.com/auth-md/docs), it named a real problem. Agents need an agent-readable way to register with third-party services at runtime, then operate against those services' APIs and tools. The parent `auth.md` file is the service's setup guide for agents: where to discover protected resource metadata, which registration methods are supported, how to claim or verify the relationship, how credentials are used, and how errors and revocation work. The [agent provider guide](https://workos.com/auth-md/docs/agent-providers) is one part of that larger system. It covers the Agent Verified path, where an agent provider such as OpenAI, Anthropic, Cursor, or a similar platform asserts a user's identity to a downstream service with an ID-JAG. This is the same topology I sketched in [ID-JAG Beyond the Enterprise IdP](/notes/id-jag-beyond-the-enterprise-idp/): the IdP Authorization Server is whoever the resource has chosen to trust for SSO and subject resolution, not just a workforce IdP. That path is the focus of this post because it is where the standards question is most interesting: how should an agent provider perform one-click setup, client establishment, and delegated API access without inventing a new grant layer? auth.md is useful as an agent-readable onboarding document. Its Agent Verified path already makes the most important standards choice: it reuses ID-JAG. Agent Verified should be an OAuth and OpenID profile, not a new grant surface. The opportunity is to lean further into the ID-JAG choice so auth.md increases the value of the OAuth and OpenID work already underway instead of becoming a long-lived parallel surface. The deployment is new. The grant surface does not have to be. The most important thing auth.md gets right is the assertion. When auth.md specifies `assertion_type: "urn:ietf:params:oauth:token-type:id-jag"` in its registration request, it is adopting an IETF draft (the [Identity Assertion JWT Authorization Grant](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/), which I co-author) that defines exactly this kind of cross-domain identity hop. ID-JAG names the IdP Authorization Server, the Resource Authorization Server, the audience binding, the typed JWT (`oauth-id-jag+jwt`), the validation rules for the assertion, and the JWT-bearer presentation path that turns the assertion into an access token. It also names the claims the assertion is expected to carry: subject, issuer, audience, jti, expiry, plus the OIDC identity claims (`email`, `email_verified`, `phone_number`, `phone_number_verified`, and so on). Picking the right primitive is the load-bearing decision in any one-click agent setup design, and auth.md picked it. This post is not arguing for a different assertion. It is arguing for completing the adoption. The agent provider is already signing an ID-JAG; the resource should accept it through the JWT-bearer grant ID-JAG was designed for, at the standard token endpoint, with the standard OAuth error model. The verified-contact requirement should be expressed as a claim predicate on the ID-JAG, not as a parallel assertion type. The revocation surface should ride on the shared identity-event channel ID-JAG's same issuer already authorizes. The hard part is done. The rest is composition. There is an ecosystem maturity caveat. ID-JAG is still a draft. CIMD is still a draft. OPC is still a draft. A symmetric trusted-issuer discovery mechanism is not written yet. auth.md is therefore not wrong to move ahead of the finished standards stack; products have to ship while standards are catching up. The question is how to move ahead without making the bridge permanent. Call the missing piece the Agent Onboarding Profile: a profile for runtime agent signup, account linking, client establishment, consent capture, delegated token issuance, events, and lifecycle. It should say how the existing OAuth and OpenID machinery composes into one click. It should not rename the token endpoint, fork the error model, or create a parallel credential exchange. If a deployment needs a setup endpoint, that endpoint should own account and client establishment, not token issuance. If the user asks an agent to update a CRM record, file a support ticket, or inspect a project board, and that service has never been connected to the agent provider before, the service needs more than an access-token exchange. The default today is for the user to paste an API key into the agent, which moves the consent prompt, the revocation UX, and the delegation audit trail to whichever side the key was generated on. What is needed instead is the agent version of "Sign up with Google": establish the user or tenant relationship, create or bind the OAuth client the agent will use, obtain delegated API access for the relevant tools, and keep the lifecycle manageable after setup. The OTP-based user-claimed and anonymous paths are useful, but they solve a different bootstrap problem: how an agent can start a registration on behalf of a user who has not yet proved control of an address or account, claim it later when the user does prove control, and upgrade access from there. That is closer to invitation, account-claim, and partial-trust registration work than to ID-JAG. This post focuses on the Agent Verified path. # What Is Actually New The deployment is a self-service signup flow where an agent provider, not the user's workforce SSO IdP, is the identity issuer that bootstraps a downstream service relationship. The agent provider acts as the IdP Authorization Server in ID-JAG's terms, even though it is not where the user originally authenticated for workforce SSO. That is exactly what the ID-JAG draft already permits: the IdP Authorization Server is whoever the Resource Authorization Server has chosen to trust for SSO and subject resolution for this hop. The OpenID Foundation's [FastFed Core 1.0](https://openid.net/specs/fastfed-core-1_0-03.html) tried a version of this for the SaaS era: an IT admin clicks through a handshake at a SaaS that configures SSO and SCIM provisioning in one ceremony. It did not become the default deployment pattern because the admin lane already had vendor-specific console flows and the consumer lane already had Sign in with Google, Sign in with Microsoft, and email signup. The scale was forgiving: a large enterprise federated with hundreds of SaaS apps over its lifetime, each set up once. The agent onboarding case is a third lane, and the volume is different by orders of magnitude. It is not admin-initiated like FastFed; the user clicks "Connect Notion" at runtime. It is not user-direct like Sign in with Google; the agent acts on the user's behalf and the agent provider attests the user's identity to Notion. Agents may need to connect to many services on demand and establish each relationship in seconds. Human-in-the-loop setup does not scale to that shape. The trust relationship is between the agent provider and the resource, established at the user's request. Inside that third lane, what is new at the protocol layer is the packaging: one click that creates or links the downstream account, establishes the agent's OAuth client identity, and obtains delegated API access. That is more than a JWT-bearer grant, but it is still a composition of existing standards. That distinction matters because the OAuth ecosystem's response should be to make the onboarding pattern easy to express in existing standards, not to fork the grant surface for it. # One-Click Agent Setup Here is the shape in concrete terms. A user tells Claude, "Connect Notion." Claude is the agent, Anthropic is the agent provider, and Notion is the downstream service. The names are illustrative; the pattern is general. ```mermaid sequenceDiagram actor U as User participant A as Agent participant AP as Agent Provider / IdP AS participant N as Notion Resource + AS participant EL as Events / Lifecycle U->>A: Connect Notion A->>N: Discover PRM + AS metadata N-->>A: Metadata + onboarding profile A->>AP: Request ID-JAG for Notion context AP->>U: Prompt for scoped Notion setup consent U-->>AP: Approve setup AP-->>A: ID-JAG A->>N: Begin onboarding with ID-JAG, consent, and client metadata N->>N: Verify issuer trust N->>N: Link or create account N->>N: Register or bind client N->>N: Record consent and scope N-->>A: Setup result A->>N: JWT-bearer grant with ID-JAG N-->>A: Access token A->>N: Call tools and APIs with delegated token N-->>EL: SSF / CAEP events EL-->>N: OPC lifecycle / RFC 7009 revocation ``` In wire-traffic terms, Claude discovers Notion's RFC 9728 Protected Resource Metadata and RFC 8414 Authorization Server Metadata. Notion advertises an agent onboarding profile and the agent providers or trust mechanisms it accepts. Claude asks Anthropic for an ID-JAG scoped to Notion, Anthropic prompts the user for this specific setup, and Anthropic returns the assertion. Notion verifies the ID-JAG issuer, resolves or creates the local account relationship, registers or binds the agent client, records the user's consent, and returns a setup result. Only after that does Claude use the standard RFC 7523 JWT-bearer grant at Notion's token endpoint to obtain delegated access. `/agent/auth` is not replaced by a single endpoint. It is decomposed into a profile: discovery, trust, identity assertion, account linking, client establishment, credential issuance, events, and lifecycle. The token endpoint handles token issuance. A setup endpoint, if present, handles the resource-local signup state. Neither endpoint should be forced to carry the whole ceremony. Layered, the composition looks like this: | Layer | Standards-based shape | | --- | --- | | Discovery | RFC 9728 + RFC 8414 + profile metadata | | Trust | Federation, registry, or user-mediated trust | | Identity assertion | ID-JAG issued by the agent provider | | Account linking | Resource-local user or tenant relationship | | Client establishment | DCR, CIMD, federation metadata, or client binding | | Credential issuance | RFC 7523 JWT-bearer grant at the token endpoint | | Events | SET / SSF / CAEP | | Lifecycle | OPC | The same question surfaces in the OAuth-for-MCP conversation. The [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization) already leans on OAuth protected resource metadata, authorization server metadata, client ID metadata documents, and dynamic client registration. What it does not define is the same onboarding ceremony at issue here: agent provider trust, account linking, client establishment, consent capture, and delegated tool access as one setup flow. auth.md is one proposed product shape for that problem. [MCP Enterprise Managed Authorization](https://modelcontextprotocol.io/extensions/auth/enterprise-managed-authorization) is another, currently deferring trust setup to manual admin configuration because no discovery mechanism exists yet. The standards answer should make these cases converge, not create separate onboarding rituals for each ecosystem. # What auth.md Already Gets Right Before mapping the layers, it is worth being specific about what the proposal gets right, because it is more than the framing. **The parent artifact.** The top-level `auth.md` file is useful because it gives agents a human-readable but structured setup guide at the service boundary. Protected Resource Metadata remains the runtime source of truth for endpoint URLs and supported flows, while auth.md explains the registration ceremony in a form agents can parse and users or developers can inspect. That is a good product shape. **Multiple onboarding paths.** auth.md is not only an agent-provider protocol. It includes Agent Verified, user-claimed, and anonymous paths. The user-claimed and anonymous flows are closer to account-claim, invitation, OTP, and partial-trust product ceremonies. The Agent Verified path is the one where the agent provider becomes an identity issuer and where ID-JAG, OAuth metadata, client registration, and federation standards apply directly. **An opinionated profile.** WorkOS is also right that "just use OAuth" is not enough guidance for integrators. OAuth is a toolbox. One-click agent setup needs a named ceremony that says which documents to fetch, which endpoints to call, what state transitions happen, what the user sees, and how revocation works. WorkOS is optimizing for immediate integrator comprehension: one file, one block, one endpoint, one credential response. That product simplicity is the right instinct. The critique in this post is not that auth.md is too opinionated or that it ignored standards. It is that the profile becomes more valuable if each piece that can be OAuth or OpenID is expressed that way as the ecosystem catches up. **What "Agent Verified" actually claims.** The brand carries weight because an agent provider can attest things a workforce IdP usually cannot: identity (the user behind this request), agent identity (the registered agent client), agent-user binding (the user linked this agent to their account), and fresh user authorization for this setup action. Only the first is what a generic OIDC IdP attests. The other three are why an agent provider is a credible IdP role, not a marketing label. All four signals fit in ID-JAG's claim space. None of them justifies a new grant type. **The consent step is real.** In workforce SSO, IT consents on behalf of the user. In "Sign up with Google," the user explicitly chose Google as their issuer for the new account. In Agent Verified, the user consented to the agent at the agent provider, not to the agent provider acting as identity issuer to this specific downstream service. The onboarding profile should make that consent step explicit, scoped to the resource, and revocable independently of the agent's overall access. auth.md has the right instincts. The mechanics need to be framed as an onboarding composition, not as a new replacement for OAuth's grant and metadata model. # Discovery and Metadata Are Mostly Already Covered The parent `auth.md` file points agents at Protected Resource Metadata and the authorization server metadata. The Agent Verified path then introduces a custom `agent_auth` block in the authorization server metadata document. Some fields map directly to existing OAuth metadata. Others are trying to describe the one-click setup profile and should be treated as profile metadata, not as a new parallel discovery system: | auth.md (custom) | Native standard | | --- | --- | | `agent_auth.skill` | Profile identifier URI; native equivalent is a profile URI in `authorization_grant_profiles_supported` (the same shape ID-JAG uses for `urn:ietf:params:oauth:grant-profile:id-jag`) | | `agent_auth.register_uri` | Onboarding profile endpoint, or a composition of Dynamic Client Registration (RFC 7591), account/tenant creation, and token issuance | | `agent_auth.claim_uri` | `token_endpoint` for the ID-JAG JWT-bearer grant, once the relationship and client are established | | `agent_auth.revocation_uri` | `revocation_endpoint` (RFC 8414 plus RFC 7009) | | `agent_auth.identity_types_supported` | `grant_types_supported` (RFC 8414), plus profile-specific advertising from the ID-JAG draft | | `agent_auth.identity_assertion.assertion_types_supported` | Resource AS: `authorization_grant_profiles_supported` includes `urn:ietf:params:oauth:grant-profile:id-jag` (ID-JAG ยง7.2), with `grant_types_supported` listing `urn:ietf:params:oauth:grant-type:jwt-bearer`. IdP AS: `identity_chaining_requested_token_types_supported` includes `urn:ietf:params:oauth:token-type:id-jag` (ID-JAG ยง7.1) | | `agent_auth.identity_assertion.credential_types_supported` | Bearer credential profile semantics; API-key-shaped credentials need lifecycle, display, rotation, and revocation rules, not a new grant type | | `agent_auth.events_supported` | RFC 8417 SET event types advertised via SSF and CAEP metadata | At the resource side, [RFC 9728 Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728) already solves the protected-resource discovery problem, and auth.md correctly adopts it. At the authorization server, [RFC 8414 Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414), extended by the ID-JAG and Identity Chaining drafts, covers the grant and token-exchange advertising. What remains is profile metadata for agent onboarding: where setup starts, which agent providers are accepted, which client-registration modes are supported, which account-linking semantics apply, and which delegated scopes or tool surfaces can be requested. That metadata should extend the OAuth discovery model rather than replace it. Discovery should name the ceremony. It should not rename the OAuth endpoints. # Credential Issuance Should Use the JWT-Bearer Grant Once setup is complete, auth.md's access exchange uses a custom JSON request to a custom endpoint: ```http POST /agent/auth HTTP/1.1 Content-Type: application/json { "type": "identity_assertion", "assertion_type": "urn:ietf:params:oauth:token-type:id-jag", "assertion": "eyJhbGc...", "requested_credential_type": "access_token" } ``` The native equivalent, defined by [RFC 7523 JWT Profile for OAuth 2.0 Authorization Grants](https://datatracker.ietf.org/doc/html/rfc7523) and profiled by [ID-JAG ยง4.4](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/), is a form-encoded request to the Resource Authorization Server's standard token endpoint, with the ID-JAG JWT (typed `oauth-id-jag+jwt` per ยง3.1) carried in the `assertion` parameter: ```http POST /token HTTP/1.1 Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer &assertion=eyJhbGc... ``` For the access-token step, every parameter in the auth.md request collapses into the standard JWT-bearer grant. The `type` parameter, the `assertion_type` parameter, the `requested_credential_type` parameter, and the JSON content type all disappear. Form encoding is the OAuth norm, and the wider OAuth toolchain (client libraries, gateways, audit pipelines) is already wired for it. The response is a standard OAuth token response: `access_token`, `token_type`, `expires_in`, `scope`. Implementation fields like `registration_id` and `registration_type` are useful inside a deployment but do not belong in the token response surface. An API key is a bearer credential with a long lifetime. Its lifecycle, display, rotation, and revocation are profile concerns, not a reason for a second grant type. That does not mean runtime signup is solved by the token endpoint alone. It means the token issuance part of runtime signup should use the token endpoint, while account or tenant creation and OAuth client establishment should be profiled explicitly around it. The token endpoint issues authority. It should not become the signup engine. # Client Establishment Is Part of Setup The place auth.md is pointing at something real is the moment before the first token is issued. WorkOS models this as a service-side agent registration and issued credential. A standards profile should say how that registration maps onto OAuth concepts: which client or client instance represents the agent for this user or tenant, how that client is bound to the agent provider, and how the resulting credential is constrained. In traditional SaaS, the equivalent step is hidden inside signup: the user clicks "Sign up with Google," the SaaS creates the account, and any application-level integration state is created behind the scenes. For agents, that hidden state includes a service-side registration plus an OAuth client, client instance, or client binding that the agent will later use to call APIs. The standards pieces exist. [OAuth Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591) defines how a client can be registered with an authorization server. The [OAuth Client ID Metadata Document](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/) draft lets a stable `client_id` point at a signed or hosted metadata document, which is a good fit for agent providers that rotate keys and publish client identity at scale. [OpenID Federation](https://openid.net/specs/openid-federation-1_0.html) can also carry metadata and policy for automated trust and registration in federated deployments. What is missing is a profile that says how these pieces compose for one-click agent setup: whether the downstream service dynamically registers a per-agent-provider, per-user, or per-tenant client or binds to an existing one; how the ID-JAG subject and tenant context link to the created account; how the client metadata document is validated and bound to the setup transaction; and which scopes, tools, or APIs the user approved during setup. Beyond that, the profile also has to handle the operational shape: how claim-token or partial-trust state is represented when setup is not yet complete, what audit events are emitted for registration state transitions, which rate limits and abuse controls apply, and how the resulting client and delegated token are revoked, rotated, or migrated later. That is useful standards work. But it is not a new credential type and not a new grant. It is a runtime onboarding profile around existing OAuth client registration, metadata, identity assertion, and token issuance. # Revocation Is Two Different Standards Depending on Intent auth.md collapses two distinct operations into a single `/agent/auth/revoke` endpoint that accepts a `logout+jwt`. Those two operations have separate standards because they answer different questions. **Revoke a specific token, right now.** That is [RFC 7009 Token Revocation](https://datatracker.ietf.org/doc/html/rfc7009) against the standard `revocation_endpoint`. A form-encoded token parameter, no JWT envelope, no event semantics. The endpoint is already advertised by RFC 8414 metadata. **Signal a cross-domain identity event the resource should care about.** That is the actual semantic auth.md is reaching for: the agent provider knows the user was deprovisioned, or the agent's authority was withdrawn, and downstream services should react. That is [RFC 8417 Security Event Tokens](https://datatracker.ietf.org/doc/html/rfc8417) delivered via [RFC 8935 push](https://datatracker.ietf.org/doc/html/rfc8935) or [RFC 8936 poll](https://datatracker.ietf.org/doc/html/rfc8936), profiled by the OpenID Foundation's [Shared Signals Framework](https://openid.net/specs/openid-sharedsignals-framework-1_0.html) and [CAEP](https://openid.net/specs/openid-caep-1_0.html). A `logout+jwt` is just a SET carrying a logout event, already covered by [OpenID Connect Back-Channel Logout](https://openid.net/specs/openid-connect-backchannel-1_0.html). auth.md acknowledges this directly: "Expect this surface to extend with SET / CAEP / RISC event communication." The long-term standards path should move this surface onto SSF and CAEP rather than keep a bespoke revocation endpoint. Resources that already integrate Shared Signals for workforce IdPs should be able to receive agent provider events through the same channel. # Lifecycle Beyond Revocation The lifecycle surface in auth.md is one operation wide: the `logout+jwt` revocation. An agent provider acting as the identity issuer for a downstream resource needs to do more than tell the resource a session is over. It needs to provision the user when the relationship starts, update claims when they change, suspend the account when the user is deprovisioned at the agent provider, and delete it when the relationship ends. [OpenID Provider Commands (OPC)](https://openid.github.io/openid-provider-commands/main.html), a draft I co-author with Dick Hardt, defines a directive channel from the OP to the RP for the full account lifecycle: Activate, Maintain, Suspend, Reactivate, Archive, Restore, Delete, Invalidate, and Migrate. Commands are signed JWTs typed `command+jwt` posted to an RP-advertised `command_endpoint`, with synchronous and asynchronous variants and metadata-based capability negotiation. Tenant-level variants exist for bulk operations across an organizational scope. The important property for the agent provider case is that **OPC requires no new trust relationship**. The OPC issuer is the same OP that signs ID-JAGs. The same `iss`, the same JWKS, the same key material the resource is already validating for setup and token exchange. Once the resource has decided to trust the agent provider as an IdP Authorization Server for ID-JAG, it has also decided to trust it as the OPC sender. One issuer, one trust relationship, one set of keys. SSF and CAEP are right for cross-domain risk signals and session-end notifications. OPC is right for lifecycle directives: provisioning, claim updates, suspension, deletion, and migration. Together they cover the event and lifecycle work auth.md points toward without requiring a bespoke revocation surface. # Claim Negotiation Has a Pending Standards Answer auth.md treats `verified_email` as a separate `assertion_type` alongside ID-JAG, and pairs it with a `missing_verified_email` error code. The name is narrower than the behavior: WorkOS says a service needs at least one verified contact, such as `email_verified` or `phone_number_verified`, to match or provision a user. Both surfaces are solving the same underlying problem: the resource cannot complete account resolution or JIT account creation without certain identity claims or claim predicates in the assertion, and there is no interoperable way for the resource to tell the IdP which claims it needs. ID-JAG already carries `email`, `email_verified`, `phone_number`, and `phone_number_verified` per OpenID Connect Core. A "verified email only" assertion is an ID-JAG with `email_verified: true`. The signature, audience, issuer, and replay protections are identical to any other ID-JAG. Treating it as a separate assertion type splits the validation path without adding a new security property. The real problem is not verified email. It is claim negotiation. Different resources need different claims: email, phone, department, employee number, license tier, custom identifiers. Some requirements are simple claim presence checks. Others are predicates, such as "email must be verified" or "either verified email or verified phone is present." The IdP has no standardized signal from the client about what the target resource requires. That gap is being addressed inside the ID-JAG draft itself. [Issue #83](https://github.com/oauth-wg/oauth-identity-assertion-authz-grant/issues/83) proposes a small, symmetric extension: - A new error code, `insufficient_identity_claims`, that the Resource Authorization Server returns when the assertion is cryptographically valid but lacks the claims needed for account resolution or JIT provisioning. The naming follows the RFC 9470 `insufficient_user_authentication` pattern: valid, but not enough. - A `required_claims` parameter on that error response, naming the missing claims as a space-separated list of claim names, in the same shape OAuth already uses for `scope`. - A `required_claims` parameter on the client's Token Exchange request to the IdP, letting the client pass the resource's requirement straight through without transformation. The end-to-end flow becomes: present a minimal ID-JAG, receive `400 insufficient_identity_claims` with `required_claims=email email_verified department employee_number` or a profile-defined verified-contact requirement, ask the IdP for an enriched ID-JAG subject to its own policy, and retry. No separate `verified_email` assertion type. No bespoke `missing_verified_email` error. The same mechanism handles resource-specific identity requirements instead of hard-coding one verified-email branch. # The Error Catalog Is Already Small on Purpose auth.md introduces several error codes. Most should map to existing OAuth errors at the protocol layer, even if the onboarding profile keeps product-level recovery states: | auth.md | RFC 6749 or RFC 9470 | | --- | --- | | `invalid_issuer` | `invalid_grant` | | `invalid_signature` | `invalid_grant` | | `expired` | `invalid_grant` | | `replay_detected` | `invalid_grant` | | `invalid_audience` | `invalid_grant` | | `invalid_client_id` | `invalid_client` | | `missing_verified_email` | `insufficient_identity_claims` with `required_claims=email email_verified`, or a profile-defined verified-contact requirement ([ID-JAG draft issue #83](https://github.com/oauth-wg/oauth-identity-assertion-authz-grant/issues/83)) | | `unsupported_credential_type` | `unsupported_grant_type` or `invalid_scope` | | `insufficient_user_authentication` | Already RFC 9470, keep as-is | OAuth deliberately keeps the top-level error catalog small and pushes specifics into `error_description`. The profile may still define recovery states for onboarding, account linking, claim completion, and user-visible remediation. But it should avoid inventing new names for cryptographic, token, and grant failures OAuth already defines. The one row that justifies a distinct protocol signal is `missing_verified_email`, where issue #83 proposes `insufficient_identity_claims` as an interoperable way for the client to retry against the IdP. For the rest, `invalid_grant` plus `error_description` is the OAuth norm, and clients should not branch on error reasons that the spec asks them to treat identically. # Profile Requirements ID-JAG is the grant. The Agent Onboarding Profile is the ceremony around it. They are not competitors; they are layers. The profile composes existing specs into a coherent one-click agent-setup flow without adding a new credential exchange. Some profile metadata is still useful, because a client needs to know whether the resource supports this ceremony and which trust, account-linking, and client-establishment modes apply. The constraint should be pragmatic rather than absolutist: use profile glue where the ecosystem has a real gap, but avoid new grant types, new token endpoints, new revocation endpoints, and duplicate names for failures OAuth already defines. What the deployment profile specifies for each requirement area: 1. **Discovery.** How RFC 9728, RFC 8414, and existing profile metadata advertise setup support. - PRM and AS Metadata carry endpoint discovery. Profile metadata carries only the ceremony-specific parts: setup support, supported trust mechanisms, account-linking modes, client-establishment modes, delegated credential types, and lifecycle/event support. - ID-JAG support is advertised with `urn:ietf:params:oauth:grant-profile:id-jag` in `authorization_grant_profiles_supported`. That URI tells a client the resource speaks the protocol. It does not tell the client which issuers, tenants, clients, subjects, audiences, or authorization requests the resource will actually accept. Trust discovery is a separate problem, and the ID-JAG draft is explicit about it. 2. **Trust.** How the service decides which agent providers it accepts. - Resolved via a companion trusted-issuer-discovery mechanism (see below), OpenID Federation, registry membership, signed metadata, or user-mediated trust. - If a new `untrusted_issuer` error is needed, it should belong to that companion trust-discovery work, not to the onboarding profile. 3. **Assertion.** How ID-JAG carries the user, tenant, agent-provider, consent, and client-binding context needed for setup. - ID-JAG draft ยง4 covers validation and claims. The deployment profile clarifies that consent and scope claims attest the user's approval at the agent provider for this audience. 4. **Account linking.** How the service decides whether this is a new relationship, an existing user, or an existing tenant connection. - Resource resolves the ID-JAG `sub` to a local account or tenant, or JIT-provisions one on first use of (`iss`, `sub`). - Missing claims return `insufficient_identity_claims` with `required_claims` (defined by ID-JAG issue #83, not this profile). 5. **Client establishment.** How service-side registration maps to a client identity. - The profile should prefer [CIMD](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/) for client identity when there is no prior relationship. The `client_id` is a URL whose document publishes client metadata, and the resource fetches and validates it on first use. - DCR, pre-registration, federation metadata, or client binding remain valid deployment choices. Client identity can stay singular per agent while per-user or per-tenant state lives in the ID-JAG `sub`, tenant context, and the resource's local account record. - Because ID-JAG is intended for confidential clients, the profile should say how the agent client proves possession: private-key client authentication, DPoP-style binding, attestation, or another asymmetric mechanism. A public URL-shaped `client_id` is identity metadata, not proof by itself. 6. **Credential issuance.** How the resource authorization server issues delegated access through the JWT-bearer grant. - Agent presents an ID-JAG at the standard `token_endpoint` via the RFC 7523 JWT-bearer grant (`assertion=`). Standard OAuth token response. - API-key-shaped bearer credentials, when supported, are returned in the same response with `expires_in` omitted and profile-defined rotation rules. 7. **Lifecycle and events.** How RFC 7009, SET / SSF / CAEP, OPC, and RFC 9470 handle revocation, events, lifecycle directives, and step-up. - Token revocation uses RFC 7009 at the standard `revocation_endpoint`. - OPC commands (Activate, Maintain, Suspend, Reactivate, Archive, Restore, Delete, Invalidate, Migrate) ride on the same trust anchor that validated the ID-JAG. - SET / SSF / CAEP carry cross-domain identity events. - RFC 9470 `insufficient_user_authentication` carries step-up challenges. 8. **Audit and abuse control.** How consent records, rate limits, security events, and conformance tests are represented. - Resource records the ID-JAG consent context (issuer, subject, `client_id`, granted scope, time, ID-JAG `jti`) for user review and independent revocation. - Rate limits at the token endpoint. Replay protection on the ID-JAG `jti`. Security events for first-use JIT provisioning. - The profile draft defines the conformance test matrix. The deployment profile's contribution is the choreography: which metadata is read, how trust is established, how the client identity is bound, how the user or tenant relationship is linked, which consent record is created, which token exchange happens, and which lifecycle channels apply. New protocol surface should be limited to the parts existing OAuth and OpenID specs do not already cover, and it should have an obvious migration path into the relevant owning spec. `insufficient_identity_claims` belongs in ID-JAG. `untrusted_issuer` belongs in the companion trust-discovery draft. A setup endpoint, if needed, belongs in the profile, but it owns account and client establishment, not token issuance. ## The trusted-issuer-discovery dependency The Trust requirement above depends on a discovery surface that does not exist yet. When a Resource Authorization Server accepts ID-JAGs, it has chosen to trust some set of IdP issuers. There is no standardized way for a client to discover that set. The closest existing surface, [`draft-mcguinness-token-xchg-target-svc-disco`](https://datatracker.ietf.org/doc/draft-mcguinness-token-xchg-target-svc-disco/), defines the inverse direction: an IdP Authorization Server advertises which target services it can issue tokens for, via a new `token_exchange_target_service_discovery_endpoint` metadata field. That solves the IdP-to-client direction. The symmetric inverse, a Resource Authorization Server publishing which ID-JAG issuers it trusts, is not yet defined. It is a generic ID-JAG ecosystem need. The same gap shows up in [MCP Enterprise Managed Authorization](https://modelcontextprotocol.io/extensions/auth/enterprise-managed-authorization), which currently defers to manual admin configuration because no published discovery mechanism exists for this direction. It also shows up in Identity Chaining and any cross-domain SSO-to-API deployment where a resource consumes assertions from multiple issuers. The right standards move is a small companion spec defining the symmetric inverse, parallel in shape to the existing target-service-discovery draft. The known security and privacy considerations carry over: enumeration attacks, trust-relationship leakage, rate limiting, and TLS posture all need the same treatment the existing draft already applies. That work belongs in its own draft, not inside the Agent Onboarding Profile. Once the companion exists, the Agent Onboarding Profile reuses it. # Why This Matters Each custom protocol surface that ships into the agent ecosystem creates the same costs the OAuth ecosystem has spent fifteen years learning to avoid: a new validation path, a new error catalog, a new revocation surface, a new metadata vocabulary, and a new fork of integrator effort. Some temporary product glue is inevitable while the standards work matures. The risk is letting temporary glue become permanent protocol. Resource services that today need to implement OAuth metadata, dynamic client registration, JWT-bearer grants, SETs, and revocation should not also need to implement a parallel `agent_auth` vocabulary that does the same things by different names. The pattern auth.md describes is real and important. One-click setup for agents acting on behalf of users against third-party services is going to be a defining shape of authorization over the next several years. The way to get there is not a parallel grant surface. It is to put the agent provider in the IdP Authorization Server role that ID-JAG already defines, discover the service through RFC 9728 and RFC 8414, establish or bind the OAuth client through existing client-registration machinery, and issue delegated access through the standard token endpoint. Then deliver events through SSF and CAEP, drive lifecycle through OPC on the same trust relationship, and profile the runtime onboarding step explicitly. auth.md should become the agent-readable ceremony document. PRM and AS metadata should remain authoritative for endpoints. The Agent Onboarding Profile should define the ceremony. ID-JAG should carry the identity assertion. CIMD, DCR, federation, or client binding should establish the client. The token endpoint should issue delegated access. SSF, CAEP, RFC 7009, and OPC should handle events, revocation, and lifecycle. The next step should be a profile draft for one-click agent onboarding, with auth.md, MCP authorization, ID-JAG, client-establishment mechanisms, OpenID Federation, SSF/CAEP, and OPC treated as inputs. The work is concrete: define the metadata fields, state machine, trust model, client-binding rules, consent record, audit events, and conformance tests that make one-click agent setup interoperable instead of bespoke. It should also be honest about sequencing: some of the inputs are drafts, one trust-discovery dependency is still missing, and early deployments will need transition behavior. Write the Agent Onboarding Profile. Keep auth.md as the document. Keep OAuth as the protocol. Use the bridge, but keep shortening it. --- # Sessions Are Not Missions Canonical URL: https://notes.karlmcguinness.com/notes/sessions-are-not-missions/ Markdown URL: https://notes.karlmcguinness.com/notes/sessions-are-not-missions.md Before a release freeze, a coding agent is approved to implement passkey login. It runs for an hour, spawns a test-repair sub-agent, and opens a pull request. Then a reviewer finds a risky migration and freezes the branch. Approval is revoked in the governance system, but the harness only knows that the workspace, task graph, and tokens are still recoverable. The next morning the session resumes, the sub-agent finishes its retry loop, and the agent updates the pull request after approval had been revoked. A modern agent can resume across machines, restart sub-agents, recover from crashes, refresh tokens, and pick up where it left off. From the outside, that looks like the agent is continuing the mission. Architecturally, it is only continuing the session. A session can prove the runtime survived. It cannot prove the mission did. A session is the checkpoint. A mission is the work order. The checkpoint tells the harness where to resume. The work order tells it whether it is still allowed to. That distinction matters because long-running agent systems persist for hours or days, run after the user closes the window, delegate to sub-agents, discover tools at runtime, and continue exercising authority across process, device, and trust-boundary changes. In those systems, treating a session as equivalent to a mission is not a UX shortcut. It is a governance failure. This is the runtime-layer version of the authority gap explored in the [Power of Attorney](/series/you-dont-give-agents-credentials-you-grant-them-power-of-attorney/), [Mission Shaping](/series/mission-shaping/), and [Mission-Bound OAuth](/series/mission-bound-oauth/) arguments: > The harness that runs the agent is not the layer that owns the mission. # What the Harness Preserves Agent platforms expose a familiar set of primitives: resumable execution, persistent workspaces, background jobs, task graphs, sub-agents, dynamic tool discovery, memory, retries, and cached tool connections. Those primitives are valuable because they let the harness reconstruct enough state to take the next step. They are also why agent products are starting to look less like chatbots and more like distributed runtimes. Each primitive solves a real problem. Resumable execution lets a long-running task survive a laptop closing. Persistent workspaces keep work in progress recoverable across restarts. Task graphs let the agent keep coordinating after a step fails. Tool connection caches let the agent skip the discovery and authentication overhead of every external call. Sub-agents let work parallelize. Background jobs let work continue while the user does something else. The user expectation behind all of this is simple. Work in progress should not be lost when infrastructure interrupts it. That expectation is correct, and it is the foundation of usable agent products. A session, in this post, means an agent harness runtime session: the state that lets execution survive infrastructure churn. It is not the same thing as an IdP session, browser session, OAuth authorization session, or application login session, though those may be adjacent to it. An agent harness session may include conversation context, task checkpoints, scratchpad memory, workspace state, tool connections, cached credentials, and orchestration state for retries or async work. All of this is good engineering. None of it explains why the agent is still authorized to keep working. # A Session Answers "Where Can the Agent Continue Working?" A session is a runtime construct. It preserves continuity across the things that interrupt execution. Most of what a session does goes unnoticed. A user closes a laptop. The process restarts on a different machine. A token refreshes, a sub-agent retries, a workspace migrates. The session storage still holds the workspace, the task graph, the cached MCP connections, and the conversation context. The harness loads that state, reconnects the tools, and the agent picks up its work. That is what a session is for. It tells the harness where the agent can continue working. | Session preserves | What that means in practice | | --- | --- | | Interaction state | Conversation context the model needs to keep reasoning | | Execution checkpoints | Where the task graph paused | | Scratchpad memory | What the agent learned during this run | | Workspace state | Files, repos, branches, and generated artifacts | | Tool context | MCP servers, APIs, connectors, and discovered tools | | Cached credentials | Tokens still inside their usable window | | Orchestration state | Queues, retries, async jobs, and sub-agent handles | The harness recovers from each disruption it sees. The mission may be experiencing events the harness will never see. | Session-layer event | Mission-layer event | | --- | --- | | Process restart | Approval revoked | | Token refresh | Release branch frozen | | Device handoff | Scope narrowed by reviewer | | Model upgrade | New risk signal raised | | Workspace recovery | Budget exceeded | | Sub-agent retry | User intent changed | The left column is visible to the harness. The right column is not. The harness can recover runtime state without learning that the mission has changed or ended. It is the same shape as a ride-share driver whose app loses signal mid-trip. The route, the GPS, and the vehicle state are on the left. The cancellation the rider sent two minutes ago is on the right. The driver completes the request the rider has already withdrawn. The session-level question is narrow: > Is enough runtime state still present for the next instruction to execute? When the answer is yes, the harness resumes. That is the right behavior at the runtime layer. A user closing their laptop should not lose an hour of work to a process restart. A sub-agent failing in a retry loop should not invalidate the parent agent's progress. A workspace migration should not cause the agent to forget where it was. Sessions are how all of that holds together. That is the question every useful harness asks. The mission asks a different question. # A Mission Answers "Why Is the Agent Allowed to Keep Working?" A mission is the approved purpose of an agent's work. It binds delegated authority to that purpose, to a declared lifecycle, and to an approval context, and it preserves the legitimacy of that work across the things that change after approval. Intent is not mission. Intent is user desire at a point in time. Mission is the durable governance object derived from intent, with bounded scope, approval context, and lifecycle. Turning intent into a mission is the work the [Mission Shaping series](/series/mission-shaping/) covers. Intent supplies the why. Mission gives the architecture something to evaluate against. The vocabulary matters. The mission is the work the user approved. It carries the record of that approval: who granted it, what it covers, when it ends, how it can be narrowed, and who inherits it. The Mission Authority Service is where the runtime asks whether any of that has changed. Revoking the mission should stop the work even if the session can still be resumed. A mission is not workflow state. Workflows track progress. Missions govern legitimacy. A workflow engine can continue after the justification for the work disappears, because its state is about what step comes next, not about whether the work should still be running. A mission-aware system cannot. The mission is the authority record that workflow state references but does not own. The mission record carries: - the purpose for which authority was granted - the evidence behind the approval - the conditions under which the authority remains valid - the bounds on delegation - the lineage of actors that inherited it - the lifecycle events that end it - the revocation semantics for stopping it before its natural end In IAM terms, these are different systems of record. Session state records runtime continuity. Token state records whether a credential is active and usable at a protocol boundary. Policy state records whether a particular request is permitted under current rules. Mission state records whether the delegated mission itself remains legitimate. Collapsing those records into the harness makes runtime recoverability stand in for authorization, revocation, and lineage. The mission-level questions are different in kind: - Is the task still authorized? - Has the risk posture changed since approval? - Is the user's current intent still reflected in the execution? - Has approval been revoked, suspended, or narrowed? - Did the scope expand without a new approval? - Can the current actor delegate further, and to whom? - Should downstream systems still trust an action presented under this authority? None of those answers are derivable from runtime continuity. A live process tells you the runtime is alive. It does not tell you the mission behind the runtime is still legitimate. That is the distinction the [Execution Mandate post](/notes/from-passports-to-power-of-attorney/) draws between identity, access, delegation, and authority. Sessions cannot answer the authority question because sessions are not the layer that owns it. # A Session Can Be Valid While a Mission Is Invalid The distinction is easier to feel through examples than through definition. Three scenarios, each from a different domain, each producing the same shape of failure. Consider an agent working under a manager's delegation for a project that takes three weeks. The agent has access to the manager's calendar, communicates on the manager's behalf with vendors, and drafts approvals that flow through the manager's name. In week two, the manager leaves the company. HR systems remove the manager's access. Payroll is closed out. The manager's email forwards to an interim contact. The agent's session storage is intact. Workspace, task graph, cached credentials, all recoverable. The delegation that justified the agent's authority is gone. The runtime is healthy. The mission has no living grantor. Now consider a security agent granted access to investigate a suspected breach. Logs are pulled, anomaly detection is run, draft incident reports are prepared. At 4pm the breach is resolved by a different team. The incident is closed in the tracking system. The agent's session continues running through 6pm because the harness queued additional analysis steps when the breach was first declared. Those steps are still in the queue. The harness has every reason to think it can continue. What it cannot see is that the reason for the investigation has ended. The session is doing exactly what sessions are built to do. The investigation does not need it anymore. And consider a user who approves an agent to draft a financial report. Mid-execution, the user discovers the report was based on stale numbers and revokes the approval. The agent's runtime is healthy. The next step in the task graph is queued. The tool connections are warm. The credentials are inside their refresh window. Nothing in the session storage knows the user has changed their mind. The harness will keep working on the report until the runtime breaks or the work completes, whichever comes first. Three different mechanisms produce the same shape. A grantor disappears. A triggering condition ends. An approver changes their mind. In each case the session preserves everything the runtime needs and nothing the governance layer would need to stop. Runtime state is recoverable. Delegated authority is no longer legitimate. The harness that asks only "can I continue?" continues. The harness that asks "should I continue?" stops. The difference between the two harnesses is whether the architecture has a layer that owns the second question. # The Failure Mode The three scenarios share a dangerous assumption. > Execution continuity equals authority continuity. Traditional sessions assume the user is nearby. Agent missions assume the user is absent. The user is asleep, in a different timezone, in another meeting, on another project, or gone from the company entirely. The agent keeps working through all of those states because the work outlives the user's attention. Session-model assumptions that worked when the user was minutes from the next interaction stop working when the user is hours or days away. Authentication freshness stops implying intent freshness. Interaction continuity stops implying engagement. Human absence is not a corner case for agents. It is the default state. Human sessions accidentally carried governance assumptions because humans naturally terminate intent. A user logging out, closing a laptop, or walking away ended runtime and authority at the same moment. Sessions never had to distinguish "can continue" from "should continue" because the human supplied the "should" by being present. The IAM stack inherited that conflation as a working assumption. Agents break the inheritance by not terminating their own intent. Short-lived chat interactions hide the assumption. The user is present, sees the next action, and closes the loop manually. Narrow copilots hide it too. Every meaningful side effect requires fresh confirmation. It breaks when work runs unattended. It breaks when work crosses domains. It breaks when child agents inherit context. It breaks when the next action changes business state. It breaks when the resource being acted on did not exist when approval was granted. The breakage has a structural cause. **Sessions model what runtime needs to stay alive across infrastructure churn.** The connection. The state. The context. The resume point. The identity check. **They do not model what governance needs.** The purpose the work was approved for. The bounds on how delegation narrows. The conditions that have to keep holding. The chain of who passed authority down. The rules for stopping it. The approval still standing in the organization. What they model is enough to continue. What they leave out is what makes continuing legitimate. Two forces make the failure mode deepen. Product pressure pushes sessions toward persistence. Engineers want resumable workflows. Users want work to survive reboots. Vendors want agents to remember more state and run longer tasks. Every incentive points the same way. Sessions get longer, more durable, more recoverable. Authority should not follow that shape. Authority is bounded by purpose, conditions, and lifecycle, not by infrastructure availability. The point of [governing the stay](/notes/governing-the-stay-not-just-the-entry/) is that authority must be terminable on its own clock, independent of whether the runtime that consumes it is still alive. The assumption concentrates at resume. Every time a session wakes, whether from a process restart, a device handoff, a token refresh, or a sub-agent retry, the harness has to decide whether to continue. Treating resume as continuation rather than as a question collapses authority into runtime state at exactly the moment the architecture should be holding them apart. When the runtime owns both execution and legitimacy, the longer-lived artifact wins. The session keeps going after the mission should have ended. That is not a bug. It is what sessions are for. # Why the Harness Collapse Is Worse The conflation is not lazy. It is rational engineering. Sessions are concrete and shippable. Missions are abstract and governance-heavy. Engineers reach for what they can build, and harness vendors reach for what they can sell. The result is the wrong default, baked in early. The harness session is a distinct authority-collapse point. Tokens are projections, not missions. Identity, access, and delegation each answer their own question. The harness session is another place where mission state quietly accumulates, and it is a worse place than the token. The reason is what each artifact is designed to do. Tokens are designed to force re-evaluation. They have explicit expiry, route through issuers on refresh, and require issuer participation for delegation. The narrowness of a token is not just a property. It is enforcement. Every refresh, exchange, or downstream issuance re-engages the authority source, whether or not authority is actually being re-checked. Sessions are designed to do the opposite. Conversation context, task graph, sub-agent handles, tool connections, cached credentials, workspace state, scratchpad memory, queues, and retries all exist to avoid re-engagement. A session is a structure built to keep work alive across the events that interrupt it. When a token is conflated with a mission, the substrate pushes back. Tokens expire. Refreshes route through issuers. The token's design surfaces periodic decision points the conflation cannot fully suppress. When a session is conflated with a mission, nothing pushes back. The substrate is engineered to suppress exactly the events the mission layer needs to detect. That asymmetry produces two structurally distinct failures. **Sessions are engineered for survival. Missions are engineered for termination.** A revoked mission absorbed into a session has to be cleaned out of the task graph, sub-agent handles, tool connection cache, orchestration queues, workspace, and scratchpad. Each of those is engineered to persist. When the artifact engineered for maximum persistence is the same artifact that carries authority, the artifact wins. The mission inherits the session's lifetime instead of the other way around. **Authority by ancestry has no token-layer analogue.** Token-based delegation requires an explicit issuance step. Session-based delegation can happen simply because a child descends from the parent's runtime graph. There is no equivalent of issuance. Delegation in sessions is implicit by default. Delegation with tokens is explicit by default. Implicit delegation cannot be attenuated, attributed, or separately revoked. Sub-agent fan-out is the failure mode the token layer does not have. Token delegation requires a signature. Session delegation requires only proximity. The token-layer collapse is the more familiar IAM failure. The harness-layer collapse is structurally different. It amplifies what the substrate is designed to suppress, and it adds a delegation path with no issuance event. # Beyond Coding Agents Coding agents make the failure easy to see. The higher-risk versions are enterprise workflows. An agent is approved to reconcile vendor invoices for an active procurement program. It discovers accounting tools through MCP, pulls invoice data, asks a sub-agent to compare contract terms, and posts reconciliation adjustments directly to the general ledger. Halfway through, the procurement program is suspended because the vendor is under legal review. The runtime session still has its workspace, task graph, cached tool connections, and retry queue. The mission no longer has a legitimate purpose. If the harness only asks whether execution can resume, the agent may continue reading invoices, posting ledger adjustments, or sending vendor remittance notifications after the business condition that justified the delegation has ended. That is the IAM failure in its enterprise form: valid runtime continuity, stale delegated authority committing irreversible state. Sub-agents amplify the collapse. The contract-comparison sub-agent inherits enough of the parent's session to do its job: workspace state, tool connections, cached credentials, ambient access, and a place in the task graph. If the harness treats the session as the mission, the sub-agent inherits authority by ancestry. There is no governed attenuation, no separate approval surface, and no separate revocation handle. The runtime graph keeps executing while children wait on tool calls or spawn their own children. The questions that matter are mission questions: - Does the contract-comparison sub-agent need separate approval to access tenant data the parent has not touched before? - Is the sub-agent still inside the original procurement scope, or has it expanded into a new domain? - Do ledger adjustments and vendor notifications require fresh consent because they commit irreversible state? - If the parent mission is revoked, do all children stop, including the ones mid-tool-call? The runtime graph cannot answer those questions by itself. It only knows what is running and what depends on what. It does not know whether each delegation remains legitimate. This is the same shape as the [client instance attribution problem](/notes/client-instances-are-actors-not-new-clients/), seen from another angle. Sub-agents are actors with their own runtime identity. The mission they inherit must be explicit, attenuated, and separately governable, not an ambient property of descending from the same session. OAuth has pieces for the cross-actor parts. [RFC 8693 Token Exchange](https://datatracker.ietf.org/doc/html/rfc8693), [Rich Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9396), and [identity assertion grants](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/) all involve explicit issuer participation. The [Actor Profile individual draft](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-actor-profile/) proposes an interoperable profile for actor chains. But none of that helps if the harness never asks for an attenuated mission because it believes the parent's session is sufficient authority for the child. Attenuation has to be more than a smaller prompt. A child mission should be a strict subset of the parent mission, inherit an expiry no later than the parent, respect delegation-depth limits, carry its own actor identity, and terminate when the parent mission is revoked. Without strict-subset checks and cascade revocation, sub-agent delegation amplifies authority faster than logging can attribute it. Open-world conditions amplify this further. As [Part 1 of the Open-World OAuth series](/notes/oauth-for-open-world-ecosystems/) argues, tools are discovered dynamically, resources appear at runtime, and execution crosses trust domains that were not paired in advance. The runtime may still be alive when the mission is no longer legitimate, or when the current work has drifted beyond what was originally approved. That is the territory [Mission Shaping Part 2](/notes/mission-shaping-is-not-enough/) covers. The older [UCON model](https://dl.acm.org/doi/10.1145/984334.984339) made the same continuity point in access-control terms: authorization conditions may need to hold during usage, not only at entry. Open-world execution makes the closed-world assumption visible by breaking it. # The Layered Model Agent harnesses are distributed execution runtimes. The "chat session" framing is too small for what they do. Their runtime concerns define execution continuity. They do not define mission legitimacy. The four systems of record introduced earlier are the spine of the architecture. Each owns a different question, and each is authoritative inside its own domain. The core rule is one line. > Sessions preserve execution. Missions preserve legitimacy. The control-plane reading is straightforward: - **Session state** records runtime continuity. The harness owns it. Workspace, task graph, scratchpad, tool connections, queues, and retries all live here. Session state answers where the agent can continue working. - **Token state** records whether a credential is currently usable at a protocol boundary. The authorization layer owns it. Tokens project bounded capabilities, with explicit expiry and forced re-engagement on refresh. - **Policy state** records whether a particular request is permitted under current rules. The policy layer owns it. Policy is evaluated per request, not per mission. - **Mission state** records whether the delegated mission itself remains legitimate. The Mission Authority Service owns it. It is the only layer that can answer whether the work the agent is doing is still authorized. On resume, the harness restores the workspace and task graph, then reads the mission handle carried in session state. It asks the Mission Authority Service whether that mission is still active and whether the next planned step is still inside its bounds. If the answer is yes, token refresh and policy evaluation can proceed. If the answer is no, queued work is canceled, child agents are interrupted, and the session remains recoverable but inert. The layers compose at runtime. A consequential action has to answer three questions: is this credential currently usable, is this request permitted under current rules, and is the mission this work belongs to still authorized? Three different questions, three different state owners, three different failure modes. Conflating them at any layer means the wrong question is being asked at the wrong time. The Mission Authority Service is the new layer. The other three already exist in mature IAM stacks. The session lives in the harness. The authorization layer lives in the AS or token issuer. The policy layer lives in the PDP. The Mission Authority Service sits above them as a control-plane object the rest of the stack consumes. It holds mission lifecycle and revocation state. It exposes an evaluable check that other layers call before issuing, before authorizing, before resuming. Write access is narrow, restricted to the principals who approved the mission and the policies that govern it. Read access is wide. Every enforcement point in the stack reads from it. What the layers fail to do when conflated is specific. Tokens absorbed into mission produce the failure [Mission-Bound OAuth Part 4](/notes/why-mission-bound-oauth-might-be-the-wrong-answer/) covers. Durable purpose gets smuggled into transport state. Policy absorbed into mission produces reconstruction-at-decision-time, where each PDP call rebuilds context that should already exist as durable state. Sessions absorbed into mission produce the failure mode this post is about. Each layer is good at its own question. None is good at the question above it. Once those boundaries are named, the failure mode is specific. The mistake is not "agents need better governance" in the abstract. The mistake is letting one of the first three layers become the system of record for the fourth. # What the Harness Owes the Mission Separating sessions from missions does not make the harness passive. It gives the harness a clearer job. Session resume must be contingent on mission validity. The mission is consulted on every path forward, not as a fallback when something else fails. The session-as-mission collapse shows up as ordinary engineering shortcuts. Each one has a governed alternative. | Anti-pattern | Governed alternative | | --- | --- | | Using the session ID as the mission ID | Carry a mission handle in session state. Never treat its presence as proof of validity. | | Treating token refresh as continuing consent | Re-check mission state on every issuance and refresh, including background-job refreshes. | | Letting sub-agents inherit parent sessions wholesale | Issue an attenuated child mission before spawning any sub-agent with new tools, resources, or side effects. | | Revoking only the visible UI session | Cascade revocation to child agents, queued work, and in-flight tool calls. | | Checking approval only at task start | Check mission state before any irreversible action, privilege change, cross-domain call, or token refresh. | | Logging tool calls without mission lineage | Tag every session event with the mission identifier so audit links runtime behavior to approved authority. | | Continuing on cached mission state when the Mission Authority Service is unreachable | Fail closed for high-risk actions when validity cannot be confirmed. | The enforcement points are distributed. The harness checks before resume, retry, delegation, and tool invocation. The authorization server checks before issuing or refreshing tokens. A gateway, sidecar, or resource server checks before protected resource access. The orchestrator checks before queued work drains into external side effects. The Mission Authority Service does not replace those policy enforcement points. It gives each of them a common authority state to consume. The failure semantics have to be explicit. Action classes should be policy-defined by reversibility, sensitivity, and business consequence. For low-risk reversible work, a harness may use a signed mission artifact or cached validity with a short maximum staleness window. For high-risk, irreversible, or materially consequential work, inability to establish mission validity should halt execution. Revocation is also not a single event. Stopping new token issuance, revoking already-issued tokens, canceling queued operations, and interrupting in-flight tool calls are separate enforcement problems. A real mission layer has to define which of those happens for each class of action. Mission state changes more than once. Termination is the simplest case. The harder cases happen mid-mission. Scope narrowing means some in-flight work is still in scope and some is not. Suspension means execution should pause but not roll back. Amendment may invalidate cached decisions while leaving the mission active. Expiry extension and condition tightening look like updates, not endings. Each transition has a different runtime consequence, and the Mission Authority Service has to distinguish them. The harness has to respond differently to each. The runtime still owns execution. It decides how to checkpoint, retry, resume, schedule, and recover work. What changes is that resuming execution becomes contingent on mission validity. Resume is not evidence of validity. Two defaults are possible at resume. Session-validated resume asks whether the runtime survived. If yes, work continues. The mission is consulted only on explicit failure. Mission-validated resume asks whether the mission is still valid. If the Mission Authority Service is unreachable or the answer is no, work pauses. The two failure modes are different in kind. Session-validated resume loses authority quietly. The agent keeps working past mission end and audit logs look clean. Mission-validated resume loses progress noisily. The agent occasionally pauses when it was still authorized. Visible failure modes can be tuned. Invisible ones cannot. Making session resume contingent on mission validity, not the other way around, is the architectural choice that pays off. Resume is an execution decision. Reauthorization is a governance decision. Do not let one impersonate the other. This is not an argument against resumable sessions, cached mission artifacts, or OAuth tokens. It is an argument against treating any of them as evidence that delegated authority still exists. # OAuth Hits the Same Wall OAuth has a parallel version of this problem. OAuth is good at capability transport: token issuance, token exchange, sender constraining, scoped access, revocation, and introspection. It moves bounded authority across boundaries. It does not define durable mission continuity, runtime mission governance, or authority re-evaluation across sub-agent fan-out. Tokens are projections of mission authority across a boundary. They are not the mission itself. OAuth mechanisms provide useful rails around the edges: token revocation ([RFC 7009](https://datatracker.ietf.org/doc/html/rfc7009)), token introspection ([RFC 7662](https://datatracker.ietf.org/doc/html/rfc7662)), JWT access tokens ([RFC 9068](https://datatracker.ietf.org/doc/html/rfc9068)), sender-constraining with DPoP ([RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449)) or mTLS ([RFC 8705](https://datatracker.ietf.org/doc/html/rfc8705)), and change-signal work such as [Shared Signals Framework](https://openid.net/specs/openid-sharedsignals-framework-1_0.html) and [CAEP](https://openid.net/specs/openid-caep-specification-1_0.html). They help with credential state, sender binding, and revocation signals. None of them makes the harness session the right place to own mission legitimacy. The fix is not only at the credential layer. It is in the protocol topology. The question shifts from "does OAuth solve this?" to "what protocol shape would?" AAuth starts from a different shape. [AAuth](https://datatracker.ietf.org/doc/draft-hardt-oauth-aauth-protocol/) makes the separation an explicit design commitment in the proposed protocol topology. The agent server runs the work. The Person Server owns mission proposal, approval, lifecycle, governance, and audit. A clear boundary between runtime and mission. The mechanism that matters is the issuance path. The agent proposes a mission to the PS. The PS approves it and returns an `AAuth-Mission` header carrying an approver identifier and a hash of the approved mission body. The agent attaches the header to subsequent resource requests. Token issuance routes back through the PS. That topology is what makes mission-validated resume possible at the protocol level. A long-lived agent runtime cannot accumulate authority on its own. In the intended topology, credential refreshes, new tool capabilities, and cross-domain hops route back through the Person Server. When the mission terminates at the PS, new issuance stops wherever the PS sits on the path, regardless of whether the agent server's runtime is still alive. The protocol topology forces the runtime to ask the question the architecture wants asked. AAuth's mission layer is still narrower than the full mission model. The remaining work is covered in [AAuth Now Has a Mission Layer](/notes/aauth-now-has-a-mission-layer/). For this post, AAuth has answered the where. The what is the harder question. # The Missing Layer Agent systems have sessions, orchestration, memory, tool inventories, and runtime continuity. Resumable, recoverable, multi-agent runtimes are what make agent products useful. What they lack is a durable governance layer that continuously answers one question: > Should this execution still be allowed to continue? That layer is not a bigger context window. It is not a richer scratchpad, a longer-lived session, or a better sub-agent router. The runtime can keep improving without becoming the right place to answer that question. Earlier posts built up that layer. An approved [Mission](/notes/the-mission-shaping-problem/) records what was granted. A [Mission Authority Service](/notes/governing-the-stay-not-just-the-entry/) owns the state and evaluates whether the mission still holds. [Protocol projection](/series/mission-bound-oauth/) carries reduced views of that state across token and signal surfaces. A [sub-agent attenuation model](/notes/client-instances-are-actors-not-new-clients/) attributes each runtime actor inside the delegation graph. The harness does not need to own any of those layers. It needs to know that it does not own them. A session that survives a laptop reboot is a useful runtime property. A mission that survives merely because the session survived is a governance bug. Agent platforms need to make session resume contingent on mission validity, not treat resume as evidence of validity. Overnight, the harness wakes the session and finds the workspace, task graph, and tokens intact. None of that matters. Every path forward routes through the mission layer. The sub-agent's retry loop wants to refresh its tokens, and the refresh routes through the Mission Authority Service. The service has marked the mission revoked. The next tool call needs an issued capability, and the issuer refuses to issue. The runtime has every piece of state it needs to continue. It does not have the authority to use any of it. The future problem is not whether agents can continue running. It is whether they should. Durable execution without durable governance is how autonomous systems silently inherit authority beyond the intent that justified it. Sessions are not missions. --- # Client Instances Are Actors, Not New Clients Canonical URL: https://notes.karlmcguinness.com/notes/client-instances-are-actors-not-new-clients/ Markdown URL: https://notes.karlmcguinness.com/notes/client-instances-are-actors-not-new-clients.md OAuth registers clients. Agent platforms run instances. The [Actor Profile (`draft-mcguinness-oauth-actor-profile`)](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-actor-profile/) closes a long-standing gap at the delegation layer: who is acting on whose behalf, with which key, across assertion grants and JWT access tokens. That work, summarized in [Standardize `act` Across Assertion Grants and JWT Access Tokens](/notes/standardize-act-across-assertion-grants-and-jwt-access-tokens/), now exists as an IETF individual draft. The next gap sits one layer below it. When a token says `client_id` is `planner-agent`, that names the registered logical client. It does not name the specific runtime that is presenting the token: which container, which agent process, which sub-agent spawned by another sub-agent five hops earlier. In production agent deployments, that is exactly the identity the resource server needs. The operational failure is easy to picture. A vendor-hosted `planner-agent` instance exfiltrates customer records using a valid token, valid user delegation, valid scope, and a matching DPoP proof. The enterprise can see that `planner-agent` acted for Alice. It cannot tell which runtime acted, whether that runtime spawned a compromised sub-agent, or whether remediation should revoke one instance or disable the whole client. > The fix is not a new client type. It is to recognize that a client instance is an actor, and to slot it into the model `act` already provides. In delegated flows, the instance appears in `act`. In self-acting flows, the same runtime profile appears in `sub`. The point is to keep runtime identity out of the client registry and inside the subject/actor vocabulary OAuth tokens already use. That is the proposal in [OAuth 2.0 Client Instance Assertions using Actor Tokens (`draft-mcguinness-oauth-client-instance-assertion`)](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-client-instance-assertion/). It builds on the Actor Profile, extends [Token Exchange (RFC 8693)](https://datatracker.ietf.org/doc/html/rfc8693)'s `actor_token` wire to other grants, and adds an `instance_issuers` field to OAuth client metadata. The client delegates instance-attestation authority to specific issuers, and the AS enforces that delegation when it decides whether an instance assertion can populate `act`. No new grant type. No new claim. No new client type. The draft is early work, not a settled specification. The rest of this post explains the approach so readers can push back on it. The [closing section](#-this-is-early-work-and-i-want-feedback) names the specific points I am asking for feedback on. # ๐Ÿ“ฆ Logical Clients vs. Runtime Instances Before the proposal lands, the distinction it leans on is worth pinning down. OAuth makes it only implicitly. A *logical client* is what gets registered with an authorization server: an application name, a set of allowed redirect URIs, a credential or key, and the policy that goes with it. `client_id = planner-agent` is a logical client. So is `slack`, `outlook-desktop`, and `salesforce-connected-app-12345`. A logical client usually lives for years. There is one of it per application, sometimes per platform variant. A *runtime instance* (or simply *instance*) is the specific running thing that realizes a logical client at a moment in time. Concrete examples: - A single container running a copy of `planner-agent`, started 90 seconds ago, scheduled on a particular node, holding its own ephemeral key pair. - A serverless function invocation acting on behalf of a user. The function definition is the client. The specific cold-started invocation is the instance. - An installed copy of a desktop application on Alice's laptop. The application registration is the client. Alice's install, identified by a device-bound key, is the instance. - A sub-agent process that a parent agent spawned to perform a narrowed sub-task, with its own key pair and its own attestation. What is *not* an instance, by this definition: - A single HTTP request or API call. Those happen *within* an instance. - A user session. A session is a binding between a user and a runtime. The runtime itself is the instance. - A tenant or workspace. Tenancy is orthogonal. One instance can serve many tenants, and one tenant can be served by many instances. The two answer different operational questions: - *"Was this application authorized for this scope?"* points at the logical client. - *"Which specific runtime, with which key, just made this call?"* points at the instance. That distinction worked when clients were long-lived servers configured by hand. It does not work for production agent fleets, where the same logical client is realized as many transient runtimes (containers, functions, agent worker processes), spawned and terminated continuously, often running on customer infrastructure rather than the vendor's, and capable of spawning further sub-agents that inherit narrower authority. A token whose only attestation about the acting party is `client_id = planner-agent` cannot answer the question that matters in incident response, audit, or policy: *which instance of `planner-agent` did this, with what key, on whose authority?* [Open-World OAuth Still Needs Mission Shaping](/notes/open-world-oauth-still-needs-mission-shaping/) frames the discovery and consent layers of this problem. [Enterprise SaaS Needs OAuth Federation Now](/notes/enterprise-saas-needs-oauth-federation-now/) frames the workload-credential layer with [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523) assertion grants and [Identity Assertion JWT Authorization Grant (ID-JAG)](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/). Both treat the client as a single registered entity. Neither names the specific runtime instance that is acting at any moment. > Client identity tells you which application is authorized. Instance identity tells you which runtime is actually exercising that authorization right now. OAuth today gives a portable answer to the first question and no portable answer to the second. The reason the second question matters is concrete. When a security operations center investigates a breach, the question is which container or function invocation made the suspect call, not which application registration covers the whole product. When an audit log records a customer-data read, the question is which agent runtime did it, not just that "an instance of the agent" did it somewhere in the fleet. When a policy engine decides whether to allow an API call, the question is whether *this* runtime, attested by a trusted issuer, with this key, is allowed to act, not just whether the application registration permits it in principle. # ๐Ÿšจ What Failure Looks Like Today To make the cost concrete, consider an incident that is plausible in production. An enterprise deploys `planner-agent` from a vendor. At 14:32, an instance of `planner-agent`, acting on Alice's behalf, calls a customer-records API and exfiltrates 80,000 records to an external endpoint. The call passes every check the resource server runs. Alice approved the scope. The token is valid. The client is registered. The resource server's policy permits the read. The DPoP proof matches the bound key. A downstream DLP system catches the exfil hours later. Investigation begins. What the audit log can answer: - Token was valid and unexpired. - `client_id` was `planner-agent`. - `sub` was `alice@enterprise.example`. - Scope `customers:read` was present and approved. - The DPoP key thumbprint matches what the AS issued. What the audit log cannot answer: - Which specific runtime of `planner-agent` made the call. The vendor runs thousands of them. - Whether that runtime was a legitimate user-authorized session at the moment of the call, or a long-lived background sub-agent that picked up a cached token. - Whether the runtime was spawned by another runtime, and by which one. - Whether the same compromise affects other customers' agents running on the same vendor infrastructure. - Whether remediation requires killing the entire `planner-agent` client (and its production traffic for every customer) or whether something narrower exists. The conversation between the enterprise security team and the vendor goes in a familiar direction. The vendor says "we cannot tell you which runtime, our internal logs do not expose that on the OAuth path." The enterprise asks "can you revoke access for our tenant only." The vendor says "yes, but it will take a coordinated rotation." The enterprise asks "what about the other tenants on the same fleet." The vendor says "we are investigating." Days pass. Customers ask the enterprise the same questions, and the enterprise has to repeat the same answers. That conversation is the failure mode. The token had everything authorization needed. It had nothing forensics needed. With the proposal, the same incident produces a different audit record. The token's actor chain names `act.sub = spiffe://vendor.example/ns/planner/instance/search-sub-92ae`, attested by `https://issuer.vendor.example` at 14:30, holding key `9aBQ...`, after being spawned by `act.act.sub = .../planner-7f3c` at 14:25. Remediation becomes targeted. Revoke `search-sub-92ae`'s attestation at the issuer. Invalidate its bound key. Leave every other sub-agent and the parent agent running. The chain tells the security team which spawn path is implicated and which sibling instances came from the same parent during the same time window. Whether the compromise propagates further becomes a tractable question instead of an open one. > The proposal does not prevent the breach. It prevents the breach from being unattributable. That distinction is the pitch. Authorization tells you whether an action was allowed. Instance identity tells you who actually took it, with enough granularity to revoke surgically and audit forensically. The defenses are bounded. The proposal does not prevent a live compromised instance from acting until its attestation expires. Issuer-side revocation stops new attestations and token renewal, but existing access tokens remain valid until expiry unless the deployment also uses OAuth revocation, introspection, or another real-time enforcement path. It does not prevent a compromised instance issuer from minting attestations for any runtime within the clients that endorsed it. It does not prevent a compromised registration path from endorsing a malicious issuer. Runtime hardening, issuer discipline, and metadata integrity remain necessary. The proposal narrows the trust boundary from "anywhere in the fleet" to the specific attested runtime, the issuer that vouched for it, and the metadata document that endorsed the issuer. That is a much smaller surface to harden. # ๐Ÿชž This Tension Is Older Than Agents The breach scenario is what the gap looks like under stress. The gap itself is older than agents. The details differ by product, but the pattern is common. The mismatch between logical client and acting runtime has been quietly absorbed inside vendor stacks for years. - **Microsoft 365.** The Office portfolio (Word, Excel, PowerPoint, Outlook, OneNote, Teams) is realized as a small set of Microsoft Entra ID application registrations used across millions of devices, browser tabs, mobile installs, and broker-mediated sessions. The same `client_id` appears on Alice's laptop, Bob's phone, and a developer's CI runner. Which runtime actually presented the token is answered by Microsoft-specific signals such as device IDs, broker state, and conditional access context, not by anything the OAuth wire format names. - **Salesforce Connected Apps.** A single Connected App registration serves an integration that can span dozens of orgs, sandboxes, and regional pods. The runtime context that matters for authorization (which process, on which deployment surface, serving which org and sandbox) is carried in custom claims and tenancy headers layered on top of OAuth rather than expressed in it. - **Slack apps.** One Slack app `client_id` can be installed across thousands of workspaces, each with its own bot user, scope grants, and runtime surface. The "which running copy, serving which workspace install" question is answered by Slack-specific identifiers, not by OAuth claims. - **Native desktop and mobile OAuth.** An installed Outlook client on a corporate laptop is `client_id = outlook-desktop`. So is the same client on a different laptop, a different OS, or a different identity. Mobile native apps have lived with the same gap since they replaced web flows. Each ecosystem has ways to compensate for the gap internally. The fixes are proprietary. They do not compose across deployments, they do not give relying parties outside the vendor's stack a portable way to reason about which runtime is acting, and they do not survive cross-domain delegation chains. > The pattern is consistent. One registered client, many runtime and tenant realities. Agents did not introduce this problem. Agents removed the option of papering over it. Workload identity federation, [SPIFFE](https://spiffe.io/), and platform broker identities have been compensating for this on the workload side for years. They produce signed attestations about which runtime is which, then bridge into OAuth through vendor-specific glue. The Actor Profile gives this work a protocol-defined slot for carrying that signal in OAuth tokens and delegation chains. Adding `client_instance` to its vocabulary is the smallest move that turns these existing compensations into something interoperable. # ๐Ÿงฑ Why "Just Register More Clients" Is the Wrong Fix Before walking through the proposal itself, the obvious alternative is worth ruling out. The natural reflex inside OAuth is to register another client per instance: every container, every spawned sub-agent, every short-lived worker becomes its own `client_id` with its own credential. That approach fails on every dimension that matters at agent scale. - **It collapses under cardinality.** Long-lived `client_id` registration assumes a small, slowly changing set with admin oversight per entry. Agent runtimes are created and destroyed in seconds. As a back-of-envelope figure, 1,000 hosted agents each spawning five short-lived sub-agents per day generates roughly 1.8 million client-registration events a year. A registry that has to keep up with that starts to look less like an administrative trust registry and more like a metrics pipeline, with all the costs: storage, indexing, sync, and lifecycle churn. - **It scatters trust.** The relying party is supposed to evaluate the registered client. If every instance is its own client, the relying party loses the ability to reason about the parent application at all, and policy fragments across thousands of indistinguishable client identifiers. - **It rebuilds the OAuth island problem.** As argued in [Enterprise SaaS Needs OAuth Federation Now](/notes/enterprise-saas-needs-oauth-federation-now/), point-to-point credentials are exactly the model federation is meant to retire. Per-instance clients re-create per-instance credentials inside every authorization server. - **It mixes layers.** The application's authority is what the user or admin approved. The instance is just the runtime that happens to be carrying that authority right now. Promoting every instance to a client conflates *who is authorized* with *who is currently executing*. The mismatch is not that OAuth's client model is wrong. The mismatch is that the client model is being asked to carry information that belongs in the actor chain. # ๐Ÿค The Pieces Already in Our Hands The interesting observation is how little needs to be invented. Each of the relevant building blocks already exists. - **`act` + entity profiles.** The [Actor Profile](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-actor-profile/) defines a typed actor chain. `act` names the party currently acting on a principal's behalf. [`sub_profile`](https://datatracker.ietf.org/doc/draft-mora-oauth-entity-profiles/) is a space-delimited string of profile values that classify each principal (`user`, `service`, `ai_agent`, and so on). `cnf.jkt` at the top level binds the token to the current presenter's public key. A new profile value, `client_instance`, fits directly into that vocabulary, sitting next to a behavioral profile such as `ai_agent` or `service`, since an instance can be both a runtime and an agent. - **RFC 8693 `actor_token` wire.** Token Exchange (RFC 8693) defines two request parameters, `actor_token` and `actor_token_type`, that let a client present a signed attestation about the party currently acting alongside the subject the request is about. Today they only show up in token exchange flows. The proposal extends those parameters to other grants (`authorization_code`, `client_credentials`, `refresh_token`, `urn:ietf:params:oauth:grant-type:jwt-bearer`), so the same wire form delivers the instance attestation regardless of how the user or workload arrived at the token endpoint. The grant types themselves do not change. The wire-form parameter choice itself is one of the open design questions. The [Open Design Choice](#-open-design-choice-actor_token-or-client_instance_assertion) section below lays out the alternative. - **OAuth client metadata.** Static registration, [Dynamic Client Registration (RFC 7591)](https://datatracker.ietf.org/doc/html/rfc7591), and [CIMD](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/) all give the AS a place to read per-client metadata. Adding an `instance_issuers` field there gives the client one place to declare, "These are the issuers I trust to attest my instances." The descriptor works the same in any of those channels. - **Workload identity federation.** [SPIFFE](https://spiffe.io/) (Secure Production Identity Framework for Everyone) and platform-issued workload assertions issue short-lived signed identifiers to running workloads based on platform attestation: which Kubernetes service account, which AWS IAM role, which CI runner. They produce signed statements about which runtime is which, which is exactly the upstream input the AS needs to validate before populating `act`. - **Attestation-based client authentication.** [OAuth 2.0 Attestation-Based Client Authentication](https://datatracker.ietf.org/doc/draft-ietf-oauth-attestation-based-client-auth/) defines a key-bound client attestation and proof-of-possession mechanism for authenticating a deployed client instance. The [Client Instance Assertions draft](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-client-instance-assertion/) addresses the next question: once an authorization server has validated runtime identity, how should that identity be represented in issued tokens so resource servers, audit systems, and downstream policy can consume it? - **DPoP / mTLS sender-constraint.** [RFC 7800](https://datatracker.ietf.org/doc/html/rfc7800) defines the `cnf` confirmation claim, which carries a thumbprint of the holder's public key. [DPoP (RFC 9449)](https://datatracker.ietf.org/doc/html/rfc9449) and [OAuth mTLS (RFC 8705)](https://datatracker.ietf.org/doc/html/rfc8705) let the holder prove control of that key on each request, so a stolen token alone cannot be replayed by a different presenter. Each instance has its own key. Each issued access token carries that instance's `cnf` at the top level when it is the current presenter. The proposal stitches these together. It does not add a parallel mechanism beside any of them. The layering is deliberate. The Actor Profile provides the token shape and actor-chain semantics. Entity Profiles provide the vocabulary for classifying the subject and actor. RFC 8693 provides the `actor_token` parameter shape. DPoP and mTLS provide sender-constraint. SPIFFE, WIMSE-style workload credentials, and platform attestation provide upstream evidence about runtimes. CIMD, Dynamic Client Registration, or static registration carry the client's endorsement of acceptable instance issuers. The instance profile ties those layers together. It does not compete with them. # ๐Ÿ”‘ Why DPoP Alone Is Not Enough A reasonable objection at this point: DPoP already binds a token to a key. If every runtime holds its own key, does not that already give per-instance separation? It does, but only at the cryptographic layer. DPoP tells the resource server "the holder of key K presented this token." It does not tell the resource server *who key K is*. That distinction is what the rest of this proposal is about. - **DPoP keys are not attested.** Any process can generate a keypair and use it as a DPoP holder key. There is no protocol mechanism in DPoP that says "this key was generated inside an attested workload identified as instance X of client `planner-agent`, vouched for by issuer Y." Without that attestation the key is opaque. The resource server can know it is talking to whoever holds the key. It cannot know that whoever holds the key is a legitimate runtime of the registered client. - **DPoP keys are not bound to a `client_id`.** The `jkt` in `cnf` says "this is the public key of the current holder." It says nothing about which OAuth client the holder belongs to. A DPoP key on its own offers no defense against cross-client smuggling. Only an attestation that names `client_id` and is endorsed by that client's metadata does. - **A DPoP thumbprint is not a name.** In audit logs, `jkt = "9aBQ..."` is meaningless without a separate lookup table mapping thumbprints to runtimes. For ephemeral runtimes that generate fresh keys on startup, no such table exists, and the thumbprint is forensically useless on its own. The breach scenario from earlier in this post is exactly what that looks like in practice. - **DPoP has no revocation surface above the key.** If a runtime is compromised, refusing to honor its DPoP key requires you to first know which runtime that key belonged to. Instance attestations move the revocation handle one level up: revoke at the issuer, and the runtime's AS-issued tokens stop renewing regardless of whether the key is still in the attacker's hands. - **DPoP carries no chain.** When `planner-agent` spawns `search-sub-92ae`, DPoP records only the current holder's key. The lineage between parent and sub-instance lives in nested `act` entries, not in a DPoP proof. Sub-agent governance, the case the post opens with, is fundamentally a chain-shape problem that DPoP cannot express by itself. mTLS with X.509-SVIDs (via `cnf.x5t#S256`) is somewhat different. A SPIRE-style issuer can sign the cert with platform attestation, the cert's SAN carries a runtime name, and certificate lifecycle or revocation machinery may be available depending on the deployment. That can address the attestation, naming, and revocation gaps from above. What it does not fix is the layer the identity lives at: it sits at the TLS connection, not in the token. It does not propagate across token exchange hops, does not appear in the actor chain, and is not visible to downstream resource servers or audit pipelines that consume tokens rather than connection metadata. The same end-state limitation applies. Sender-constraint is necessary for this proposal to do its job. The top-level `cnf` binding (`cnf.jkt` for DPoP, `cnf.x5t#S256` for mTLS) is what makes the live sender constraint enforceable. But sender-constraint alone is not sufficient. The instance assertion is what gives the key meaning: which attested runtime, of which client, vouched for by which issuer, spawned by which parent. Strip the assertion away and you are back to "the holder of some key did this," which is exactly the audit dead end enterprises are stuck in today. > DPoP secures the key. The instance assertion identifies the keyholder. Both are needed. # ๐Ÿ”ง The Trust Delegation Model The remaining question is how the instance assertion gets its meaning. The trust shape behind it has three parties: 1. **The OAuth client** publishes the issuers it trusts to attest its instances. This is an `instance_issuers` array in the client's metadata, with each entry naming an issuer URL, expected subject syntax (such as a SPIFFE trust domain prefix), and key material discovery. The metadata reaches the AS through whatever channel the deployment already uses: CIMD when the `client_id` is a URL, Dynamic Client Registration when registration is programmatic, or a static client record when registration is admin-driven. The descriptor format does not depend on which channel was used. 2. **The instance issuer** authenticates the runtime (typically through a workload identity federation mechanism) and signs an instance assertion that names both the instance and the `client_id` it belongs to. Per-client minting is a hard requirement. An issuer must not be able to mint an assertion for a client that did not endorse it. This is what prevents cross-client smuggling. A breach of one product's issuer cannot produce assertions usable by another product unless that other product independently endorsed the same issuer. 3. **The authorization server** resolves the client's metadata (CIMD URL or its local registration store), validates the assertion against the client's published instance-issuer set, verifies the JWS, and binds the resulting access token to the instance's key via top-level `cnf`. The assertion is short-lived and audience-bound, and the AS rejects replayed assertion IDs. ```mermaid sequenceDiagram participant Client as OAuth Client participant Issuer as Instance Issuer participant Runtime as Runtime participant AS as Authorization Server Note over Client: Setup Client->>AS: Publish instance_issuers in metadata
(via CIMD, DCR, or static) Note over Runtime,Issuer: Runtime startup Runtime->>Issuer: Request attestation Issuer->>Runtime: Signed instance assertion
(client_id, sub, cnf) Note over Runtime,AS: Token request Runtime->>AS: Grant + instance assertion AS->>AS: Resolve client metadata AS->>AS: Verify assertion.iss endorsed
by client.instance_issuers AS->>AS: Verify assertion.client_id matches AS->>Runtime: Access token
(act + cnf bound to runtime key) ``` Three concerns travel together by design. The first is identity, the runtime's stable name. The second is attestation, a trusted issuer's claim about that identity. The third is key binding, proof the runtime holds the key the AS bound to the issued token. Each pair without the third loses force. Identity without attestation is an unfalsifiable self-claim. Attestation without key binding can be replayed by anyone who exfiltrates the assertion. Key binding without attested identity is the sender-constraint-alone case ruled out earlier. The proposal couples all three because each gap is what an adversary exploits. The shape also inherits one assumption worth naming. The AS must trust the client's metadata to be authentic. Whoever decides which clients are allowed to publish which `instance_issuers` is the meta-trust authority. For statically registered clients, that is the AS administrator. For Dynamic Client Registration, it is the AS's DCR authorization policy. For CIMD, it is the chain of trust establishing that the metadata at the `client_id` URL is what the legitimate client actually authored. Instance attestation is only as strong as the integrity of the registration that endorsed the issuer. The proposal does not solve registration integrity. It inherits whatever the deployment already has. A client metadata document carrying `instance_issuers` looks the same whether it was fetched via CIMD or stored in the AS from a static registration. In this example, the instance issuer signs JWT assertions using keys published at `jwks_uri`, while `spiffe_id` constrains the allowed subject syntax for runtime names. The CIMD case is shown here: ```json { "client_id": "https://planner.assistant.example/oauth/client", "client_name": "Planner Agent", "redirect_uris": ["https://planner.assistant.example/cb"], "token_endpoint_auth_method": "private_key_jwt", "instance_issuers": [ { "issuer": "https://issuer.assistant.example", "jwks_uri": "https://issuer.assistant.example/jwks", "subject_syntax": "spiffe", "trust_domain": "assistant.example", "spiffe_id": "spiffe://assistant.example/ns/agents/*", "signing_alg_values_supported": ["ES256"] } ] } ``` The instance assertion itself is a JWT signed by the instance issuer, naming the instance and the client. It carries `cnf` so the AS can sender-constrain whatever it issues to the key the instance actually holds: ```json { "iss": "https://issuer.assistant.example", "sub": "spiffe://assistant.example/ns/agents/instance/planner-7f3c", "sub_profile": "client_instance ai_agent", "aud": "https://as.example.com/token", "client_id": "planner-agent", "cnf": { "jkt": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs" }, "iat": 1773075000, "exp": 1773075600, "jti": "9c4d3e..." } ``` Two structural rules matter. First, the instance assertion itself must not contain `act`. It represents direct identity of the runtime, not a delegation chain. Second, `client_id` in the assertion must match the OAuth client involved in the request. That equality is what prevents one client's instance attestation from being smuggled into another client's flow. If the issuer is not endorsed by `instance_issuers`, the `client_id` does not match, or the `cnf` key does not match the presenter, the AS rejects the assertion. The current draft's wire form at the token endpoint reuses RFC 8693's actor token parameters across grants. An authorization code redemption with an instance attestation looks like this: ```text POST /token Content-Type: application/x-www-form-urlencoded DPoP: grant_type=authorization_code &code= &redirect_uri=https%3A%2F%2Fplanner.assistant.example%2Fcb &client_id=planner-agent &actor_token= &actor_token_type=urn:ietf:params:oauth:token-type:client-instance-jwt ``` No new grant type. The grant remains `authorization_code`. The current draft carries the instance in the RFC 8693 actor-token slot, extended to this grant. # ๐Ÿ’ก What This Looks Like in Tokens The Actor Profile defined three structural cases for delegation. Adding instance identity gives them sharper meaning. One structural note before the cases. RFC 8693's `act` names the party acting on behalf of a subject. In delegated flows (Cases 1 and 3), the runtime is that acting party and belongs in `act`. In the self-acting case (Case 2), there is no separate subject, so the runtime belongs in `sub`. The `client_instance` profile value classifies the runtime in either position. The result is one vocabulary for runtime identity without changing the meaning of `sub` or `act`. ## Case 1: Delegation (User Authorizes a Client Instance) Alice signs in to `planner-agent`. The runtime that picks up her session is a specific instance. The issued access token carries Alice as the principal, the instance in `act`, and the instance's key as the live sender constraint. ```json { "iss": "https://as.example.com", "aud": "https://api.example.com", "client_id": "planner-agent", "sub": "user-alice", "sub_profile": "user", "scope": "hotels:search hotels:book", "cnf": { "jkt": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs" }, "act": { "iss": "https://issuer.assistant.example", "sub": "spiffe://assistant.example/ns/agents/instance/planner-7f3c", "sub_profile": "client_instance ai_agent", "cnf": { "jkt": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs" } }, "exp": 1773076800 } ``` The resource server gets two answers from one token. *Whose authority is being exercised?* Alice. *Which runtime is exercising it?* The `planner-7f3c` instance, holding the key the AS bound the token to. ## Case 2: Self-Acting Instance A backend ingestion worker is its own principal. There is no user. The instance assertion goes in directly as the subject identity, not as an actor wrapped around a user. ```json { "iss": "https://as.example.com", "aud": "https://api.example.com", "client_id": "ingestion-worker", "sub": "spiffe://platform.example/ns/ingest/instance/worker-04f1", "sub_profile": "client_instance service", "scope": "ingest:write", "cnf": { "jkt": "kfL3oTu5Vd8gtPKjB5q2XnPmGrLfRFAzTQbm2qj9SxQ" }, "exp": 1773076800 } ``` `act` is absent because no other principal authorized this runtime. The instance is the principal. The classification (`client_instance service`) tells the resource server what kind of runtime it is and that it was attested via the instance flow rather than registered separately as a client. ## Case 3: Sub-Instance via Token Exchange This is the case the client model genuinely cannot represent. A parent agent instance spawns a narrower sub-agent instance to perform a bounded sub-task. The sub-agent presents the parent's token as `subject_token` and its own instance assertion as `actor_token`. The new token preserves the chain: the user is still the principal, the sub-agent is the current actor, the parent agent is recorded as the prior actor. ```json { "iss": "https://as.example.com", "aud": "https://api.example.com", "client_id": "planner-agent", "sub": "user-alice", "sub_profile": "user", "scope": "hotels:search", "cnf": { "jkt": "9aBQfFxYJVD8cAvLFAzTQbmzELkFAYW8bqvVvRsBnsg" }, "act": { "iss": "https://issuer.assistant.example", "sub": "spiffe://assistant.example/ns/agents/instance/search-sub-92ae", "sub_profile": "client_instance ai_agent", "cnf": { "jkt": "9aBQfFxYJVD8cAvLFAzTQbmzELkFAYW8bqvVvRsBnsg" }, "act": { "iss": "https://issuer.assistant.example", "sub": "spiffe://assistant.example/ns/agents/instance/planner-7f3c", "sub_profile": "client_instance ai_agent", "cnf": { "jkt": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs" } } }, "exp": 1773076800 } ``` The same `client_id` covers both runtimes because they are instances of the same logical agent product. The chain inside `act` shows which specific instance acted now and which one acted before, with each instance's key recorded at its hop. The top-level `cnf` is the live sender constraint, exactly as the Actor Profile specified for the [agent-to-tool example](/notes/standardize-act-across-assertion-grants-and-jwt-access-tokens/#-the-canonical-cross-domain-case) in the prior post. Each token exchange hop performs two coupled actions: the `act` chain extends with the new current actor, and the top-level `cnf` shifts to that instance's key. Prior instance keys remain inside nested `act` nodes as delegation history. The processing rules from the Actor Profile apply unchanged. > Sub-instances are not a new taxonomy. They are actor chain entries with a profile value that says "this hop is a runtime, not a logical principal." # โš™๏ธ Resource Server Processing Whatever chain produced the token (single-domain delegation, self-acting workload, or sub-instance fan-out), the resource server validates it the same way. Resource server logic stays close to what the Actor Profile already specified, and the instance profile only sharpens what the existing rules look at. ```text input: access_token jwt dpop_proof jwt // required when token.cnf.jkt is present 1) Validate token (sig, iss, aud, exp) per JWT AT profile (RFC 9068). 2) Verify top-level cnf.jkt against the DPoP proof per Actor Profile. 3) If token.act present: actor_profiles := parse_profiles(token.act.sub_profile) If "client_instance" in actor_profiles: // The current actor is a specific runtime of token.client_id evaluate policy.allow_instance(token.act.sub, token.client_id) evaluate policy.allow_delegate(actor_profiles, parse_profiles(token.sub_profile)) else: // Logical actor (e.g. another service identity) evaluate policy.allow_actor_for_subject(token.act.sub, token.sub) 4) If token.act absent and "client_instance" in parse_profiles(token.sub_profile): // Self-acting instance evaluate policy.allow_instance_self(token.sub, token.client_id, token.scope) 5) Optionally walk nested token.act.act... for audit. Each nested cnf.jkt records the key binding of a prior actor in the chain. 6) Enforce decision. ``` `client_id` is still part of the input. It identifies which application's authorization is being exercised. The instance subject in `act` (or in `sub`, for self-acting) tells the resource server which runtime is doing the exercising. The combination, not either alone, is what supports policies like "only instances attested by issuer X can call this endpoint" or "this scope is allowed for instances under SPIFFE prefix Y." In Cedar that policy shape looks like: ```cedar // Allow only production runtimes of the planner agent, // attested by the assistant-domain instance issuer. permit ( principal, action == Action::"payments:read", resource ) when { context.token.client_id == "planner-agent" && context.token.act.iss == "https://issuer.assistant.example" && context.token.act.sub_profile.contains("client_instance") && context.token.act.sub like "spiffe://assistant.example/ns/agents/production/*" }; ``` Three token-claim checks plus one prefix match against the SPIFFE namespace. None of this is expressible interoperably from standard OAuth token data alone without instance identity in the chain. # ๐Ÿ›ก๏ธ What Does Not Change The point of the proposal is the surface area it does not move. - **`client_id` remains the trust anchor.** The OAuth client is still the registered application. Authorization decisions, scope grants, consent records, and admin policy continue to attach to the client, not to instances. - **No new grant type.** `authorization_code`, `client_credentials`, `refresh_token`, `jwt-bearer`, and `token-exchange` keep their existing flows. An instance-attestation input is made available on those flows, but the grant types themselves are unchanged. - **No new claim shape.** `act`, `sub_profile`, and `cnf` already exist. The proposal adds one profile value (`client_instance`). Everything else on the token side is reuse. - **No new client type.** Clients do not become "instance-aware clients" or any other new category. They register as today (statically, via Dynamic Client Registration, or via CIMD) and optionally include `instance_issuers` in their existing metadata. - **OAuth revocation does not change.** [RFC 7009](https://datatracker.ietf.org/doc/html/rfc7009) revocation and [RFC 7662](https://datatracker.ietf.org/doc/html/rfc7662) introspection work as before. Issuer-side revocation is a complementary upstream control. The protocol does not need to learn about instances. It already knows about actors. We just need to put instances in that slot. # ๐Ÿชง Open Design Choice: `actor_token` or `client_instance_assertion`? The current draft uses RFC 8693's `actor_token` parameter, extended to grants beyond token exchange, to deliver the instance assertion at the token endpoint. A reasonable alternative is a dedicated request parameter, `client_instance_assertion`. The access-token result is the same either way, so the question is only which token-endpoint wire form is cleaner. The two options produce identical access tokens. Both place the validated runtime in `act` for delegated flows or in `sub` for self-acting flows. The actor model on the token side does not change. What changes is the wire form at the token endpoint. ## The Two Wire Forms With `actor_token` (the current draft, shown for an authorization code redemption): ```text grant_type=authorization_code &code= &client_id=planner-agent &actor_token= &actor_token_type=urn:ietf:params:oauth:token-type:client-instance-jwt ``` With `client_instance_assertion`: ```text grant_type=authorization_code &code= &client_id=planner-agent &client_instance_assertion= ``` The dedicated parameter form is shorter because the parameter name carries the type meaning that `actor_token_type` carries explicitly. ## Why the Draft Chose `actor_token` The draft documents the reasoning in [its appendix on this question](https://datatracker.ietf.org/doc/html/draft-mcguinness-oauth-client-instance-assertion#rationale-no-instance-assertion-param). The load-bearing arguments: - **Avoiding token-endpoint fragmentation.** Reusing `actor_token` / `actor_token_type` keeps the wire surface unified instead of adding per-profile request parameters. - **Reuse of an existing Token Exchange slot.** RFC 8693 already uses `actor_token` for the party currently acting in a token exchange request. The current draft extends that same input shape to other grants instead of creating a second way to present actor evidence. - **Future profile extensibility.** Profiles can define their own `actor_token_type` URIs without each needing a new request parameter. - **Semantic continuity.** In delegated flows, `actor_token` carries the evidence that becomes the issued token's `act` entry. In self-acting flows, the same evidence is represented in `sub`. The parameter names the acting-party evidence without forcing every output token to contain `act`. ## Why `client_instance_assertion` Might Be Better - **Semantic precision.** The parameter name describes exactly what is being presented: proof of the concrete runtime instance acting for the registered client. - **Avoids stretching `actor_token` semantics in self-acting flows.** In a `client_credentials` request, the runtime is not an actor in the RFC 8693 sense. It is the principal. A neutrally named parameter avoids that stretch. The choice is bounded to the wire form. Everything in [What Does Not Change](#-what-does-not-change) still applies regardless of which parameter wins. > The wire parameter says what is being proven. The actor chain says what it means. Whether those two things share a name (`actor_token`) or have separate names (`client_instance_assertion` plus `act`) is the question this section is asking for feedback on. # โš–๏ธ The Alternative: Promote `client_instance` to the Protocol The wire-form choice in the section above stays inside the actor model: both `actor_token` and `client_instance_assertion` deliver runtime identity into the existing `act` claim. A more structural alternative would be to promote `client_instance` to a top-level OAuth concept of its own. That path is worth describing because it is the obvious next move once you accept that instances matter. That path looks like this: - A new request parameter such as `client_instance_id` at the token endpoint, paired with a `client_instance_assertion`. - A new top-level access token claim, `client_instance`, distinct from `client_id` and from `act`. - A new grant type, or a parameter retrofit across every existing grant, signaling that an instance attestation is being presented. - A new client registration mode so authorization servers can tell instance-aware clients apart from legacy ones. - New introspection fields, new revocation scopes, and a new consent dimension once instances are visible to end users. It has surface appeal. Instances become visible at the protocol layer the same way clients are. A first-time implementer reading a token would see an "instance" field labeled as such, rather than a typed entry inside `act`. Tooling that today renders `client_id` could render `client_instance` next to it without learning anything about actor chains. For people whose mental model starts at OAuth 2.0 and stops short of Token Exchange, that is a real ergonomic gain. The cost is that every layer of the stack has to learn the new concept. Authorization servers, libraries, introspection endpoints, audit pipelines, consent UI, policy engines, API gateways, and downstream resource servers all need new code paths. The Actor Profile already paid the cost of teaching the ecosystem typed, key-bound delegation, and the new concept overlaps almost entirely with what `act` already represents: a non-principal identity exercising authority on behalf of someone, with its own type, key binding, and chaining rules for sub-actors. Promoting `client_instance` to the protocol layer would create a parallel mechanism alongside it. Two ways to say "the runtime currently acting is X." Two introspection shapes to learn. Two policy entry points. Two places where audit chains can disagree about who acted and when. The actor framing chooses a smaller tradeoff: one profile value (`client_instance`), one actor-token type or one dedicated request parameter depending on the wire-form choice, one optional client metadata field (`instance_issuers`) that rides on whatever registration channel the deployment already uses, and the rest is reuse. AS code that already validates `act` and `cnf` extends naturally. Resource server policy that already evaluates `act` adds one branch for the `client_instance` profile. An introspector that does not know about instances still sees a structurally valid actor chain and renders it as one. > The choice is not about whether instances are important. The choice is about whether to make instance identity a new thing the protocol must learn, or to treat it as a specific kind of actor the protocol already knows how to carry. Spending the protocol-extension cost twice for the same expressive content is the failure mode worth avoiding. The full design space, summarized: | Approach | What changes | Ecosystem cost | |---|---|---| | Status quo (per-vendor extensions) | Per-vendor proprietary claims, headers, and runtime-identity formats | High: adapters needed everywhere, no cross-vendor composition | | `actor_token` (current draft) | One new `actor_token_type` URI | Low: AS validates a new type, no new request parameter | | `client_instance_assertion` (alternative) | One new request parameter | Low: AS validates a new parameter, same `act` representation downstream | | Top-level `client_instance` claim | New request parameter + new access-token claim + new policy / introspection / audit paths | High: every layer of the stack learns a new concept | # ๐Ÿ—๏ธ Why This Is a Primitive The proposal's restraint is what makes it load-bearing for downstream work. Instance identity is a primitive that several open lines of work depend on: - **[Mission-Bound OAuth](/series/mission-bound-oauth/)** needs runtime identity to bind a mission to the specific running thing carrying it. "Bound to the planner-agent client" is not a binding. "Bound to instance `planner-7f3c` until its attestation expires" is. - **Cross-app access ([XAA / ID-JAG](/notes/enterprise-saas-needs-oauth-federation-now/))** needs per-runtime policy scoping (production vs. development, customer-tenanted vs. shared) without registering separate clients per class. - **Audit, observability, and SOC tooling** can finally answer "which runtime did this." That is the question the failure scenario opened with. Without instance identity in the token, that question has no answer. Each of these initiatives already consumes `act`, `sub_profile`, and `cnf`. Putting instance identity in the same vocabulary means none of them needs a separate plumbing pass. # ๐Ÿค” Common Questions **Does this require DPoP on every issued token?** The instance assertion always includes `cnf` so the AS can sender-constrain whatever it issues. Whether the issued access token is itself sender-constrained downstream is a deployment choice. Bearer-style downstream tokens still work. A resource server that does not enforce sender-constraint will simply not benefit from the live key check. Most deployments that go to the trouble of attesting instances will want sender-constraint downstream, because that is what makes "this specific instance is allowed to present this token" enforceable instead of just informative. **Does this work for opaque tokens and introspection (RFC 7662)?** Yes, if the authorization server exposes equivalent actor-profile fields in the introspection response. The opaque token itself does not carry the profile the way a JWT access token does. A resource server introspecting an opaque token evaluates `act`, `sub_profile`, and `cnf` from the RFC 7662 response instead of from token claims. **Is this only for AI agents?** No. The same model fits CI/CD runners, serverless invocations, mobile and desktop installs, and broker-mediated sessions. AI agents make the gap urgent because they multiply runtime cardinality and fan out into sub-agents. The underlying mismatch between logical client and runtime applies anywhere the same registered client is realized as many runtimes. **Can different instances of the same client carry different scopes?** Scope grants attach to the client and (for delegation) the user. Per-instance scope narrowing happens through token exchange: a parent instance trades for a sub-token with reduced scope, the sub-instance presents that, and the resource server sees the narrower scope alongside the new actor entry. The Actor Profile's chain semantics handle the rest. **Who runs the instance issuer?** Whoever owns the runtime platform. In practice that is the agent product vendor for hosted agent fleets, the cloud provider for managed serverless and Kubernetes (often via SPIFFE or platform workload identity), and the application vendor for desktop and mobile broker scenarios. The OAuth client lists those issuers in its `instance_issuers` metadata, which is what tells the AS that an attestation from that issuer is acceptable for this client. **Does this require CIMD?** No. CIMD is one delivery channel for client metadata. Static admin-provisioned registration and Dynamic Client Registration (RFC 7591) carry the same `instance_issuers` field equally well. CIMD is convenient when the `client_id` is already a URL, because it keeps the metadata under the client's own control, but the descriptor format and the AS processing rules are the same regardless of how the metadata reached the AS. **Can the instance assertion authenticate the client too?** Yes, optionally. A client can declare `client_instance_jwt` as a `token_endpoint_auth_method` value, and the AS will accept the endorsed instance assertion as both runtime identity and client authentication. This eliminates the need to provision a long-lived client credential per runtime. Clients with stable credentials (`private_key_jwt`, mTLS) can keep them and let the instance assertion ride alongside, identifying the runtime without replacing the credential. The simplification is opt-in. # ๐Ÿ“ฌ This Is Early Work, And I Want Feedback Both drafts are early individual submissions. The [Actor Profile](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-actor-profile/) and the [Client Instance Assertions draft](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-client-instance-assertion/) are on datatracker, but neither is an OAuth WG document. Before either should move forward, the approach needs to survive review by people who build, operate, or buy real systems. The thing I am most trying to test is the central standards question: should OAuth represent runtime instance identity as actor-profile data, or does it need a first-class protocol surface of its own? My thesis is that runtime instance identity is best treated as a typed actor in the existing `act` chain, not as a new top-level OAuth concept. If that framing is wrong, if there is a class of deployment, a threat model, an existing pattern, or a sub-protocol I have not accounted for, I want to hear about it now, before more weight gets written into the draft. Specific things I am uncertain about: - Whether the trust delegation model (client endorses issuers in its metadata, issuer mints with a `client_id` binding, AS validates against the endorsement set) is the right shape, or whether something closer to per-attempt attestation-bundle propagation fits better. - Whether the runtime attestation should ride in `actor_token` (the current draft choice, reusing the RFC 8693 parameter) or in a dedicated `client_instance_assertion` parameter. The [Open Design Choice](#-open-design-choice-actor_token-or-client_instance_assertion) section above lays out both wire forms, the reasoning for the current pick, and the case for switching. - Whether `client_instance` belongs alongside `user`, `service`, and `ai_agent` in the `sub_profile` namespace, or whether it deserves a different classification axis. - Whether the failure scenario reflects what enterprises and vendors actually face, or whether it overdramatizes a problem that vendors have already solved internally in ways I am not seeing. If you operate an authorization server, build a resource server or API gateway, run an agent platform, or buy enterprise SaaS at scale, your read on this is what I most want. Counter-examples are more useful than agreement. Tell me what is wrong, what is overstated, what is missing, and what is unworkable. Logical clients describe what was authorized. Instances describe what is acting. The model that already names the second thing is the actor chain. The question for the OAuth community is whether putting instances in that slot is enough, or whether runtime identity deserves a new protocol surface despite the extra machinery that would require. If this lands, an enterprise security team responding to an incident pulls the access token and immediately sees which runtime acted, which issuer attested it, which key was bound, and which sub-agent spawned which. Revocation targets the specific compromised attestation without disrupting the rest of the fleet. SOC tooling consumes the actor chain as portable JSON instead of per-vendor adapters. Cross-app access policies scope to runtime classes (production vs. development, customer-tenanted vs. shared) without registering separate clients per class. Mission-bound OAuth and other higher-layer governance work compose against a primitive already in the token, in the same vocabulary every party understands. The point is not novelty. It is portability for the runtimes acting across enterprise systems. --- # Enterprise SaaS Needs OAuth Federation Now Canonical URL: https://notes.karlmcguinness.com/notes/enterprise-saas-needs-oauth-federation-now/ Markdown URL: https://notes.karlmcguinness.com/notes/enterprise-saas-needs-oauth-federation-now.md [Vercel's April 2026 incident](https://vercel.com/kb/bulletin/vercel-april-2026-security-incident) was not a network breach. It was three hops through already-granted application access: a compromised third-party AI app, a corporate Google Workspace account, then internal environments and environment variables. No firewall bypass required. That pattern is not unique to Vercel. In the November 2025 Salesforce-connected app incident, [Gainsight's postmortem](https://www.gainsight.com/blog/how-we-accelerated-a-year-of-security-work-in-weeks/), based on Mandiant's investigation, documented 285 tokens from a single integration, some issued as far back as October 2017. In 2022, [GitHub disclosed](https://github.blog/news-insights/company-news/security-alert-stolen-oauth-user-tokens/) attackers abusing stolen OAuth user tokens issued to Heroku and Travis CI to access private repositories. **Different incidents, same exposure:** long-lived delegated access is still scattered across app-specific systems the enterprise cannot inventory or shut down quickly. Most responses to incidents like these focus on long-lived credentials, visibility, and auditing. Those are real problems. They are also symptoms. > The deeper failure is authority placement. Rotating credentials and auditing grants improves operations inside each OAuth island. It does not change the fact that every new integration creates another island with its own authority to mint, renew, and revoke access. The failure is not bad operations inside each island. The failure is a model that keeps creating islands and placing authority inside each one independently. Enterprise SaaS has never really fixed that layer. Single Sign-On (SSO) centralized login, but it did not centralize delegated access across apps. Each new integration still tends to create another client, another credential or refresh-capable artifact, another approval surface, and another vendor-local revocation workflow. The result is another OAuth island. Enterprise SaaS needs to move from point-to-point OAuth integration to OAuth federation. For services and workloads, the model is already mature enough to adopt now. For user-delegated cross-app access, Cross-App Access (XAA) is the right standards direction. The goal is not foreign-token portability. The goal is issuer-signed assertion in, local access token out, with more of the governance around long-lived delegated access moved upstream to the enterprise issuer. # Why OAuth Islands Are A Real Security Problem Imagine an internal assistant that reads a Jira issue, updates Salesforce, and posts the result to Slack. What sounds like three useful connections is, from an enterprise security perspective, usually three separate sources of long-lived delegated access outside the enterprise Identity Provider (IdP). An `OAuth island` is an app-specific system for long-lived delegated access outside the enterprise IdP, with its own client, credential, grant, renewal, and governance lifecycle. The enterprise did not gain one governed cross-app access plane. It inherited another OAuth island to inventory, govern, and shut down. Every integration creates another OAuth island outside the IdP. That is why separate integrations are a real security problem. The issue is not that one OAuth flow is too complicated. The issue is that point-to-point integration keeps manufacturing hidden trust inventory outside the IdP, one app at a time. When an OAuth grant creates long-lived delegated access, the enterprise has effectively created a new standing access path. The prompt is brief. The access it creates often is not. Multiply that by the estate, not by one demo flow. Three apps in one workflow means three OAuth islands. Ten important workflows across the same SaaS estate do not create one shared control plane; they create dozens of long-lived delegated access relationships with different clients, scopes, storage locations, and revocation paths. Add app marketplaces, internal brokers, Zapier-style automation, and other integration runtimes, and the hidden trust inventory grows faster than most security teams can enumerate it. Trust is often granted in a moment and exploited months or years later. That is why the Gainsight timeline matters. [Gainsight's postmortem](https://www.gainsight.com/blog/how-we-accelerated-a-year-of-security-work-in-weeks/) documented 285 tokens from a single integration spanning eight years. [Nudge Security's research](https://www.nudgesecurity.com/post/nudge-security-unlocks-thousands-of-saas-security-profiles) finds an average of 16 OAuth grants per employee, four of them carrying data-sharing permissions. In a thousand-person organization, that is sixteen thousand OAuth grants. No security team manually governs that. That is the operational meaning of an OAuth island. It is not just another integration. It is another place where access has to be found, understood, and shut down under pressure. Security teams do not just have to ask "was this token stolen?" They have to ask which app created it, where the credential or refresh-capable artifact is stored, which runtime is still holding it, which vendor console controls revocation, whether the grant is still renewable, and whether downstream automation copied the same access into another system. Attackers no longer need network adjacency if long-lived delegated access already gives them application adjacency. Once a standing grant or refresh-capable path exists across apps, lateral movement becomes an authorization problem as much as a network problem. Production systems and sensitive data should not sit one low-friction third-party authorization away from external tooling. Each island also inherits the same technical weaknesses: shared secrets instead of asymmetric client authentication, bearer-style artifacts reusable if copied or stolen, sparse governance APIs, and no single revocation surface. These are not independent problems to fix vendor by vendor. They are what failed authority placement looks like in production. Fixing them inside each island separately is the credential hygiene response. Moving authority upstream is the federation response. That sprawl did not happen by accident. Product-led growth, app marketplaces, and one-click integration flows made OAuth adoption frictionless by design. Every "Connect with [SaaS]" button shortened time to value and quietly extended the enterprise security perimeter. Any control that depends on a user remembering to mark the right secret, pick the right scope, or revisit the right admin screen has already failed at SaaS scale. The problem is not one bad vendor or one misconfigured flow. It is an operating model that manufactures more long-lived delegated access than the enterprise can see, govern, or shut down. # What OAuth Federation Means Here `OAuth federation` means issuer-signed assertion in, local access token out. A downstream SaaS authorization server accepts an issuer-signed assertion from an enterprise issuer as input to mint its own local access token. The SaaS still decides local authorization and still issues its own tokens. What moves upstream is more of the client authentication, grant governance, and renewal authority. That is a narrower and more viable move than asking every SaaS to accept every other vendor's access token. SSO federation centralizes login. OAuth federation centralizes more of the governance around long-lived delegated access. That distinction matters because the enterprise IdP often already governs authentication, but not what happens later inside each SaaS product when a client requests a grant, stores a refresh token, or keeps renewing access for months. Enterprises often think they centralized trust when they bought SSO. In practice, they centralized login while long-lived delegated access kept proliferating underneath it. In practice, that means the enterprise issuer becomes the place where more client authentication, assertion issuance, and renewal authority live, while the SaaS remains the place where resource-specific authorization happens. The issuer can decide which clients or workloads are even eligible to request assertions, under what conditions assertions may be issued, how keys are managed, whether risk signals block issuance, and when renewal authority should stop. The SaaS still decides whether the presented assertion is acceptable for its own APIs and what token it is willing to mint from it. That separation is what makes the model viable: governance moves upstream without turning every SaaS into a passive resource server for foreign tokens. That shift changes the blast shape in incidents like Vercel, Gainsight, and GitHub. Federation does not erase local access-token risk, but it reduces how much standing delegated access has to live in vendor-local systems in the first place. Fewer shared secrets and refresh-capable paths have to be recreated app by app, renewal authority moves closer to the issuer the enterprise already governs, and shutdown depends less on visiting every vendor console one by one. Two deployment lanes matter here. Workload and service federation is already possible in many cases with generic assertion grants such as [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523). User-delegated cross-app federation is the harder problem, and that is where XAA matters most. XAA is being standardized in the IETF through [Identity Assertion Authorization Grant (ID-JAG)](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/). OAuth federation is the broader architectural pattern; XAA is the user-delegation standards direction inside it. ## Workload And Service Federation For workloads, services, and many agent-to-SaaS cases, the excuse phase is over. Assertion grants such as [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523) already let a client present an issuer-signed assertion to a SaaS token endpoint and receive a local access token in return. That is issuer-mediated federation for machine access. It moves key management, workload identity, and assertion issuance upstream while the SaaS keeps control of its tenant, scopes, and API contract. In a concrete service flow, a CI job, backend service, or agent runtime can obtain an issuer-signed assertion from the enterprise issuer, exchange it for a local access token, and avoid storing another shared secret in a runtime or build system. The SaaS still mints the token and still enforces its own API policy. The same model works for a deployment pipeline that needs to open a Jira ticket, update a status page, and post to Slack without embedding three separate vendor secrets in the build system. That is already enough to replace many shared-secret integrations with a more governable model. Buyers should start treating that as baseline machine-access support, not as advanced federation plumbing. If a SaaS product still requires every service, pipeline, or agent runtime to register another app-local client and store another long-lived secret, the customer is still being asked to operate another OAuth island. ## XAA For User Delegation For user delegation, XAA is the SSO moment for cross-app access. If OAuth federation is the architecture, XAA is the clearest standards expression of that architecture for user-delegated cross-app workflows. It is the right bet because it standardizes trust reuse, not token sharing. The enterprise keeps the issuer relationship it already operates. The downstream SaaS keeps its own authorization server and its own local access tokens. The resource server does not have to learn another vendor's access-token format or accept a foreign token directly. The workload and service lane is more mature today. The user-delegation lane has now become urgent enough that XAA should be treated as the next enterprise default, not as a distant standards project. Consider the Jira/Salesforce/Slack assistant from the opening. Today that workflow requires three separate user-delegated authorization setups: the user redirected into Atlassian for consent and a Jira-local refresh token, redirected into Salesforce for consent and a Salesforce-local refresh token, and redirected into Slack for consent and a Slack-local refresh token. Three vendor consoles to configure. Three standing delegated grants to govern. Three separate revocation paths when the workflow is decommissioned or the user's access changes. As those workflows multiply across an enterprise and agents begin running them continuously on users' behalf, the user-delegation surface compounds the same way the workload surface does. XAA addresses this directly: the user authenticates once to the enterprise issuer, and each downstream SaaS accepts the resulting identity assertion as the input to its own local delegated grant. The approval surface consolidates at the enterprise issuer. The standing grant state moves upstream. The three downstream SaaS products still mint their own local access tokens and still enforce their own API policy, but the enterprise controls the authorization input rather than rebuilding it separately inside each one. The downstream SaaS should be able to treat an enterprise-issued identity assertion as the input to a local delegated grant, instead of forcing every cross-app workflow back through another isolated vendor-local authorization setup. For XAA-style user delegation, the comparison looks like this: | Area | Point-to-Point User Delegation | XAA-Style User Delegation | |---|---|---| | Trust setup | Client registration and delegated access are configured separately in each SaaS product | The enterprise issuer and downstream SaaS establish trust for identity assertions, even if some local SaaS policy or client configuration remains | | User authentication path | The user is redirected into each SaaS product's own authorization flow | The user authenticates to the enterprise issuer, and the downstream SaaS accepts the resulting identity assertion as the grant input | | Approval and governance | Consent and admin approval are scattered across vendor consoles | Approval can move toward enterprise-administered policy, pre-authorization, or issuer-layer governance, depending on deployment | | Long-lived delegated state | Vendor-local refresh tokens and app-specific delegated grants accumulate per workflow | Local access tokens can still stay local, but grant and renewal governance move upstream, reducing vendor-local standing delegation | | Resource server impact | Each SaaS resource server depends on a separate app-local delegation flow | The resource server still depends on its own local access-token contract and does not need to accept a foreign access token | | Response and shutdown | Revoke, rotate, and audit one app at a time | Cut off issuer-side assertion issuance or renewal authority centrally, then let local access tokens expire | Notice what does **not** change. In XAA, the downstream SaaS still decides what scopes, tenant rules, and resource access it will allow. That is the key bet: change the grant path without giving up downstream authorization or asking resource servers to accept foreign tokens. **Why XAA is the right bet:** - It reuses issuer trust the enterprise already established for SSO instead of rebuilding long-lived delegated access inside every app. - It preserves downstream SaaS sovereignty because the SaaS still mints and enforces its own token. - It avoids foreign-token portability, so resource servers do not need to accept another vendor's access token format. - It gives the market an incremental adoption path instead of requiring a full inter-vendor re-architecture before anything improves. This is why OAuth federation beats more point solutions. The enterprise should not have to rebuild the same access model separately inside Atlassian, Salesforce, Slack, and every other SaaS product just to let one approved workflow cross app boundaries. OAuth federation is not valuable because it removes every downstream token risk. It is valuable because it centralizes the parts of the model that are most expensive to govern and most inconsistently implemented across vendors. Without federation, the enterprise inherits the OAuth maturity of every vendor it authorizes. # Why Agents Change the Economics Point-to-point OAuth integration survived because the integration set was bounded. Human-operated SaaS deployments had a finite set of important apps, a finite set of approved integrations, and a slow enough rate of change that organizations could tolerate too many vendor-local clients, secrets, grants, and refresh paths without the whole model collapsing. Agents break that assumption. As argued in [OAuth for Open-World Ecosystems](/notes/oauth-for-open-world-ecosystems/), agents do not operate in closed worlds. They discover tools and protected resources at runtime, encounter authorization servers they were never pre-configured to know, and expand the number of token acquisition paths far faster than any human integration team can manage manually. That changes the economics as much as the security model. In a point-to-point world, every new tool, app, or API means another client registration, another secret or key, another consent or approval surface, another renewal path, another audit record, and another incident-response dependency. When one human workflow turns into fleets of agents and sub-agents traversing dozens or hundreds of apps and resources, the trust surface does not grow linearly. It compounds. Agents do not simply make the old model noisier. They make it operationally bankrupt. Organizations hit a form of authorization bankruptcy: more long-lived delegated access relationships than they can inventory, review, rotate, or revoke before the next wave is already in production. At that point, failing to federate stops being tolerable architecture debt. It becomes an existential scaling problem. This is also why the adoption chicken-and-egg is finally breaking. Historically, apps were reluctant to pay the implementation cost of federation for one or two IdPs, and IdPs were reluctant to invest until enough apps supported it. Agents are collapsing that standoff because neither side can afford to keep building point-to-point trust at agent scale. [Model Context Protocol (MCP)](https://modelcontextprotocol.io/specification/2025-11-05/basic/authorization)'s [Enterprise Managed Authorization](https://modelcontextprotocol.io/specification/2025-11-05/basic/authorization#enterprise-managed-authorization) and similar platform moves are building OAuth federation into the agent integration layer because the alternative does not scale. Agents force the market to confront what enterprise SaaS could previously postpone: point-to-point long-lived delegated access is no longer economically or operationally viable as the default. SSO followed the same pattern. It became table stakes because SaaS moved application identity outside the reach of Active Directory and the corporate network, and the old model no longer scaled. Over time, SSO stopped being a premium feature and became part of the baseline for serious enterprise software. Long-lived delegated access is now in the same position one layer down. SSO solved the question of who signed in. It did not solve who can keep acting later across app boundaries. Agents are forcing that question into the open. # What The Transition Looks Like This is a staged transition, not a single cutover. **Now:** use generic assertion grants where vendor support exists. [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523) already gives workloads, services, and many agent-to-SaaS integrations a path where a client presents an issuer-signed assertion at a SaaS token endpoint and receives a local access token in return. That does not solve the whole end-to-end problem, and it does not eliminate all per-product registration. But it is real progress away from per-app shared secrets and toward upstream trust. It also enables more just-in-time enterprise access flows, where services, pipelines, and agents can obtain short-lived access when needed instead of depending on long-lived credentials that were provisioned in advance. **Next:** adopt XAA as the standards direction for user-delegated cross-app access. The current IETF work for that is [ID-JAG](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/). It supports the same enterprise outcome, upstream trust with downstream local access-token issuance, but vendor support is less mature. The service and workload lane is more mature today. The user-delegation lane is mature enough in standards shape, market need, and buyer pressure that XAA should now be treated as the direction to build toward. It can support architectures where approval and governance move closer to the enterprise identity layer, but the exact approval and consent model remains a deployment choice, not something the protocol guarantees by itself. The pattern also extends beyond the workforce IdP to CIAM platforms and internal service identity wherever the downstream authorization server already trusts an issuer for SSO and subject resolution. See [ID-JAG Beyond the Enterprise IdP](/notes/id-jag-beyond-the-enterprise-idp/). The transition has three layers. Now is assertion-based federation for workloads, services, and many agent integrations inside today's SaaS reality. Next is stronger standardization for user-delegated cross-app access through XAA, with ID-JAG as the current IETF work. Later is the broader open-world agent problem, where clients discover tools and authorization servers at runtime and OAuth has to keep evolving beyond today's mostly closed-world SaaS assumptions. That later stage does not make the urgency any less. It makes the need to stop building new islands even clearer. Pieces of this are shipping today, but unevenly. [Okta's Cross-App Access docs](https://help.okta.com/oie/en-us/content/topics/apps/apps-cross-app-access.htm) show a user-delegated path that still assumes an existing app relationship, [Microsoft Entra](https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation) shows workload identity federation in production, and [Salesforce](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_jwt_flow_ca.htm&language=en_US&type=5) shows JWT Bearer support with prior approval. That is not the finished cross-SaaS end state, but it is enough to prove the building blocks are real and deployed. The important market point is that enterprises do not need to wait for a perfect end state to change direction. The transition can start anywhere a SaaS token endpoint is willing to accept an issuer-signed assertion instead of forcing another shared secret or another long-lived vendor-local credential. Each time that happens, one more integration moves from another OAuth island toward an issuer-mediated model. The strategic shift is cumulative even before the market reaches a fully standardized cross-app model. **For workloads and services, adopt issuer-mediated federation now. For user-delegated cross-app access, adopt XAA as the standards direction.** # What OAuth Federation Does Not Do OAuth federation is scoped by design, not by compromise. It changes where long-lived delegated access is governed. It does not replace every control in the stack, and it should not. That scope is what makes the model viable for downstream SaaS adoption. - **It does not remove local authorization.** Downstream SaaS products still decide what scopes, tenant rules, and resource access they will allow. The SaaS keeps its authorization server and its own local access-token policy. - **It does not eliminate registration.** Some SaaS products will still need local trust configuration to accept issuer-signed assertions. Federation reduces ongoing credential sprawl; it does not collapse setup to zero. - **It does not rescue weak issuer governance.** Moving authority upstream only helps if the enterprise identity layer actually governs clients, workloads, approval, and renewal well. A poorly governed issuer just centralizes the failure point without reducing the risk. - **It does not create a single global kill switch.** Cutting off issuer-side assertion issuance or renewal authority is more powerful than hunting vendor consoles one by one, but local access tokens may still need to expire, be revoked, or be subject to tenant-side controls. - **It does not eliminate token risk at the edge.** Local access tokens still benefit from short lifetimes, sender-constraint, and stronger runtime controls. These are not objections to federation. They are the design choices that make the model work: the enterprise takes more control of the grant path, the SaaS keeps control of resource authorization, and neither side has to give up what it owns. The right mental model is "federate the grant, keep the token local." # Stop Building Islands The April 19, 2026 Vercel incident did not create this problem. It made it harder to ignore. The immediate step is practical: pull an inventory of active OAuth grants and refresh-capable artifacts across your top SaaS integrations, ask when the oldest credential was issued, and ask whether you could cut off renewal without visiting every vendor console. If you cannot inventory, revoke, and shut down long-lived delegated access centrally, you are still operating OAuth islands. But inventory is triage, not the strategy. It tells you how many islands you already have. It does not change the model that keeps creating new ones. The strategic shift is now clear. For workloads and services, issuer-mediated federation should be a baseline enterprise requirement. For user-delegated cross-app access, XAA should become the standards answer. Chief Information Security Officers (CISOs), identity leaders, and security buyers should force both shifts into the market: make OAuth federation part of the Request for Proposal (RFP), part of vendor security reviews, and part of renewal conversations. That means asking directly: Can you accept issuer-signed assertions and mint local access tokens for workloads and services today? Do you support XAA, or do you have a credible XAA path for user delegation? Do you expose asymmetric client authentication, grant inventory, centralized revocation, and emergency shutdown paths? The core buyer question is not whether each vendor runs its island well. It is whether the island still has to exist. > After SSO standardized login, enterprise SaaS should standardize cross-app access around the same pattern: issuer-signed assertion in, local access token out. Vendors that still require another app-local client, another stored long-lived artifact, and another vendor-local revocation path for each workflow are not offering a stronger default. They are asking customers to carry another OAuth island. The market does not need better-run islands. It needs vendors to stop building them. --- # AAuth Now Has a Mission Layer Canonical URL: https://notes.karlmcguinness.com/notes/aauth-now-has-a-mission-layer/ Markdown URL: https://notes.karlmcguinness.com/notes/aauth-now-has-a-mission-layer.md When I wrote [Mission Architecture on AAuth](/notes/mission-architecture-on-aauth/), AAuth was a proposal with a strong identity and choreography story and an open question at the governance layer. My argument was that it looked like a better clean-sheet substrate than OAuth for agent authorization, but that it still did not clearly define where durable task authority would live. The published [draft-hardt-aauth-protocol-01](https://datatracker.ietf.org/doc/draft-hardt-aauth-protocol/) changes that argument materially. The earlier post made a narrow claim: > AAuth looked like a better clean-sheet substrate than OAuth for agent authorization, but it still did not clearly remove the need for a Mission-like governance object above the protocol. That claim is no longer accurate as written. Mission is now a first-class concept in the published protocol. There is a mission proposal and approval flow, an `AAuth-Mission` header, mission-aware token choreography, and PS governance endpoints for interaction, permissions, and audit. The protocol moved toward exactly the kind of governance layer the earlier post said was missing. That does not mean the architecture is finished. What it means is that the question has shifted. The draft closes the "where is the mission layer?" question. It does not close the "what authority does the mission actually confer?" question. The gap is no longer whether AAuth needs a mission layer. The gap is whether the mission layer it has is semantically rich and lifecycle-complete enough to do the work that durable task authority actually requires. The honest answer is mostly the latter. That is what this post works through. Before getting into the details, the current state of the draft is straightforward: | Question | Does the draft answer it? | Notes | | --- | --- | --- | | Is there now a mission object in the protocol? | Yes | Mission proposal, approval, mission log, and `AAuth-Mission` header are defined. | | Can systems correlate actions to the same mission across hops? | Yes | Mission correlation travels through the `approver` and `s256` values. | | Can independent systems enforce the same mission semantics consistently? | No | Mission meaning still depends on local interpretation and local policy. | | Can mission revocation guarantee runtime stop? | No | Runtime stop still depends on token lifetime, revocation support, and execution architecture. | # What the Earlier Post Got Right The earlier post got three big things right, and they still hold. First, AAuth is a cleaner protocol substrate than OAuth for agent systems. Signed requests with proof of key possession, PS-mediated deferred authorization, and explicit clarification as a first-class operation all provide a stronger base shape than stretching classic OAuth. The chaining difference matters most. OAuth Token Exchange (RFC 8693) does give OAuth a delegation chain story, but those chains are not PS-mediated, not correlated to a governance object at each hop, and not visible to a central authority that can enforce mission context across the full chain. AAuth's chaining is architecturally different in ways that matter specifically for mission governance. Second, better protocol choreography is not the same thing as durable authority governance. A protocol can be conversational and chain-aware without defining a durable authority object. Third, the missing piece looked like a Mission-like governance object rather than just another purpose string or another token field. That point is now partly validated by the protocol itself, because the published draft introduces Mission as a first-class governance concept. That is the core delta. # What This Closes From the Earlier Argument The published draft now gives Mission a real place in the protocol: - a **Mission** as a scoped authorization context - mission creation and approval at the **Person Server (PS)** - an `AAuth-Mission` request header - mission context that can be carried in resource tokens and auth tokens - mission lifecycle and mission log semantics - governance endpoints for interaction, permissions, and audit This is a meaningful change. The older post said AAuth still appeared to need a Mission-like governance object above the protocol. The published draft now has one in the protocol. The architecture is no longer only about agent identity, proof-of-possession, and token choreography. The mission-aware flow in `draft-hardt-aauth-protocol-01` works as follows: 1. The agent obtains an agent token from its agent server. 2. If it wants governance, it sends a mission proposal to the PS's `mission_endpoint`. 3. The PS may involve the user through review, approval, or clarification. 4. On approval, the PS returns an `AAuth-Mission` header containing the `approver` and `s256` hash of the approved mission body. 5. The agent includes that `AAuth-Mission` header on later resource requests. 6. A mission-aware resource can include the mission object in the resource token it returns. 7. The agent presents that resource token to the PS as part of the authorization flow. 8. The PS evaluates the request against mission context before issuing an auth token directly or federating with the resource's AS. The approved mission is now a real protocol object. The mission blob must include: - `approver` - `agent` - `approved_at` - `description` It may also include: - `approved_tools` - `capabilities` That is enough to say the published protocol now has a mission layer in a meaningful sense. It also means several claims from the earlier post need to be revised. Mission is now clearly first-class in the protocol. Approval is part of the core governance flow. Mission context survives the initial approval event and travels through token choreography. The PS has a genuine governance role rather than serving only as a broker in authorization exchanges. That governance role is architecturally significant. The PS is playing policy-definition and decision roles in the mission governance layer, while also acting as the user's interaction proxy for clarification and consent. Combining those roles in a single entity keeps the governance stack coherent but also makes the PS a critical dependency for every authorization decision in the chain. That concentration has real implications for availability, trust model separation, and deployment topology that are worth keeping in mind as the architecture matures. That is real progress. # What Still Does Not Close The published draft materially changes the comparison. It does not eliminate the harder parts of the Mission argument. ## 1. Mission is still text-first, not authority-model-first This is now a real mission layer, but it is still not a portable authority model. The approved mission body includes structured top-level fields, but the actual mission scope still centers on a Markdown `description`. That is a design choice, not an oversight. Understanding why it matters requires being clear about two fundamentally different models for what a mission is in a multi-system context. **The AAuth model: mission as governance object, with enforcement coordinated but not fully shared.** In the published protocol, Mission sits at the PS as a governance artifact. The PS approves it, carries it, correlates it, and governs it. The AS and Resource, as downstream systems, receive mission context and participate in token issuance and enforcement. What the protocol does not provide is a shared, portable authority derivative that all of them evaluate the same way. Each system still combines mission context with its own local policy and its own interpretation of the request. The PS can refuse future token issuance, and any resource can refuse a request, but the draft does not require independent systems to converge on the same interpretation of what "inside the mission" means. **The Mission Authority Model: mission as shared enforcement artifact, compiled from approved intent.** The mission series argues for something different. Approved intent should produce a machine-evaluable derivative: a structured representation of which resource classes, actions, constraints, stages, and delegation bounds are actually inside the mission. That artifact travels with or can be derived from the mission. Multiple PSes, ASes, and Resources evaluate consistently against the same bounded authority envelope. Enforcement is shared because the authority model is shared. The difference is not just technical. It is a question of what "mission governance" actually guarantees. In the AAuth model, governance means the PS approved the intent and can revoke or log against it. Whether a specific downstream action was actually inside that intent is still evaluated through local policy and local request interpretation at each participating system. The protocol does not guarantee that independent implementations will converge on the same answer about mission containment. In a shared enforcement model, governance means the authorized boundary can be evaluated consistently by independent systems. A compliant implementation that approves an out-of-scope request is wrong, not just permissive. OAuth readers will recognize the pattern. Two OAuth authorization servers can treat the same `scope` value differently and still be spec-compliant, because OAuth standardizes scope syntax, not scope semantics. AAuth inherits that problem at a higher semantic level: mission prose is richer than a scope string, but still not a shared authority model. The practical consequences show up in three places. **Audit.** Mission correlation โ€” was this request associated with an approved mission? โ€” is achievable with the AAuth model. Mission containment โ€” was this request actually inside the mission's authority? โ€” requires the shared enforcement model. Correlation supports traceability. Containment is what high-governance environments actually require. **Attenuation.** If mission authority lives in prose, there is no formal way to prove that a downstream token is a subset of the approved grant. A PS can assert it and a resource can accept it, but neither can prove it. A Mission Authority Model is the prerequisite for making attenuation provable rather than merely asserted. This is also what makes gap #4 on downstream attenuation harder than it looks: the attenuation problem cannot be cleanly solved without first solving the authority model problem. **Cross-domain enforcement.** Two independent PSes can correlate the same mission through the hash. They cannot enforce it consistently unless they share a semantic model of what the mission permits. The AAuth protocol makes cross-domain mission correlation interoperable now. Cross-domain enforcement remains local to each deployment. The draft's optional `approved_tools` field does not close this gap. A tool list is a permission set, not a bounded authority envelope. It says which tools may be called. It does not define the resource classes those tools may touch, the actions they may perform within those classes, the stage constraints on when each applies, or the explicit exclusions the approver intended. This is also where [Rich Resource Requests (R3)](https://dickhardt.github.io/AAuth/draft-hardt-aauth-r3.html) matters, even though it does not fully solve the authority-model problem. R3 is a companion draft that defines structured authorization vocabularies for resources: mappings to MCP, OpenAPI, gRPC, and similar formats that let resources describe their operations precisely. Resources publish R3 documents; the PS or AS evaluates them; auth tokens carry back the result as specific granted operations (`r3_granted`) and operations requiring per-call parameter validation (`r3_conditional`). The semantic richness is for the authorization layer, not the agent: - **The Resource** describes what it offers in precise vocabulary - **The AS** evaluates what the mission permits against that vocabulary - **The user** sees curated human-readable consent text from the `display` section - **The agent** carries an R3 document hash and acts on the result Agents carry R3 document hashes without reading the definitions themselves. The authorization layer does the semantic work server-to-server. What R3 contributes is a more structured authorization surface. Instead of comparing mission prose against bare scope strings, the PS can compare mission intent against a precise vocabulary of what the resource actually permits. That narrows the gap between approval and enforcement without closing it. It is a more structured surface for local evaluation, not a shared authority model. It is worth being direct about why AAuth makes this tradeoff. Standardizing a compact mission object with human-readable description is tractable today. Standardizing a universal authority language is not, at least not before there is enough implementation experience to know what fields, selectors, constraints, and stage semantics actually need to interoperate across real deployments. The AAuth approach lowers coordination cost sharply and makes early adoption realistic. The Mission Authority Model approach is more correct about what strong governance eventually requires. Both can be true at the same time. The practical path is layered. Early deployments use mission text plus PS-local heuristics. Stronger implementations add locally compiled authority artifacts behind the PS. `R3` improves authorization precision in the meantime by giving the PS structured resource vocabularies to reason against. A later companion profile can standardize a portable Mission Authority Model once there is enough operational evidence to know what actually needs to interoperate. The current draft creates the protocol slot. It does not fill it. ## 2. Lifecycle exists, but remains intentionally narrow In `draft-hardt-aauth-protocol-01`, a mission has two states: `active` and `terminated`. Completion is the expected path into termination. The draft defers revocation mechanics, delegation tree queries, and administrative interfaces to a companion specification. That is meaningful progress over no lifecycle at all, but also a deliberately minimal model with real consequences. **The AAuth model: mission has existence and completion, not rich lifecycle semantics.** The protocol establishes that missions exist, that they can be approved, and that they end. What it does not establish is *why* they end or what that means for participants downstream. Termination is termination. Normal completion looks the same as operator cancellation, which looks the same as policy suspension, which looks the same as business-driven revocation. Each arrives at the same protocol state: `terminated`. Outstanding token requests, in-flight agent operations, and queued work all see the same signal regardless of the reason. What they do with it is up to each implementation. **The mission series model: lifecycle states carry semantic meaning that downstream systems need.** A richer lifecycle model would likely need to distinguish states that have different operational implications, for example: - *Completed*: task finished successfully; outstanding tokens may drain normally - *Suspended*: temporarily paused for review; downstream operations should queue, not abort - *Cancelled*: business-driven stop; outstanding work should roll back where possible - *Terminated for policy violation*: immediate halt; already-issued tokens should be treated as invalid even if not yet expired - *Timed out*: deadline exceeded; tokens within window may complete, new ones should not issue These are not academic distinctions. They determine what downstream agents and resources should do when they receive the signal. **The concrete failure mode.** An agent is three days into a multi-step financial workflow. A compliance officer wants to pause it pending investigation, not cancel it. Under the current protocol there is no pause state. The compliance officer terminates the mission. The agent's running operations see `terminated` and must decide locally whether to abort, checkpoint, or drain. The downstream AS stops issuing tokens. The agent has no protocol-level signal distinguishing "hold and wait for review" from "stop and clean up." The compliance officer now manages the suspension outside the protocol, through operational coordination, direct system access, or implementation-specific admin tooling. That is exactly the kind of problem a lifecycle model exists to solve. **Why AAuth makes this tradeoff.** A minimal state model is much easier to implement and much easier to align across vendors. Every additional lifecycle state multiplies both the implementation surface and the edge cases requiring interoperability. Prematurely standardizing administrative semantics before deployments have real operational experience risks standardizing the wrong model. The draft is right to defer this. The spec also gives a concrete architectural reason: there is no push channel from the PS to the agent. AAuth agents poll; they do not receive notifications. A suspended state would require the agent to learn the mission has resumed, which is not possible without polling indefinitely with no indication of when to stop. Terminating and creating a new mission scoped to the changed circumstances is the spec's recommended path. The cost is that every deployment independently invents lifecycle semantics that should eventually be interoperable. A mission terminated in org A's PS means something locally specific. Org B's systems, participating in that mission's execution, receive a `terminated` signal and interpret it by their own rules. When the ecosystem eventually needs lifecycle semantics to interoperate across deployments (and high-governance environments will require this), each deployment's bespoke model becomes a migration problem. The current draft is strong enough to anchor mission existence and completion. It is not yet strong enough to anchor the full administrative lifecycle that durable task authority requires. The companion specification is the right place for that work. The gap is real in the meantime. ## 3. Revocation is stronger in the control plane than in the runtime plane The PS now has meaningful revocation authority: - terminate missions - deny future token requests - revoke outstanding auth tokens through revocation endpoints where implemented That is a real and important capability. The failure mode is not in the control plane. It is in the gap between control-plane revocation and runtime stop. **The AAuth model: the PS can withdraw authority; whether execution stops is an implementation question.** When a mission is terminated, the PS refuses new token requests. Outstanding auth tokens can be revoked through the revocation endpoint where that revocation path is implemented. The protocol authority is withdrawn. One clarification on the token model matters here. Resource tokens in AAuth are not access tokens. They are credentials issued by the resource server to the agent so the agent can request an auth token from the PS. Auth tokens are what the agent presents to the resource for access. In three-party flows the PS issues them directly. In four-party flows the PS federates with the resource's AS, the AS issues the auth token, and the PS delivers it to the agent. In both cases the PS is on the critical issuance path: it can refuse to federate or refuse to issue, stopping new auth tokens from reaching the agent. For outstanding tokens already held by the agent, the protocol defines a revocation path in both flows where revocation endpoints are implemented. In three-party flows the PS can call the resource's revocation endpoint with the auth token's `jti`. In four-party flows the PS can do the same, calling the resource's revocation endpoint directly and optionally notifying the AS. The runtime-stop argument does not depend on the AS being the revocation hop. It depends on whether revocation support exists and how quickly it propagates. All AAuth auth tokens are also proof-of-possession: they are bound to the agent's signing key and useless without it. This means the revocation window is a risk only for the legitimate agent still holding the private key, not for an attacker who might have intercepted the token. The practical revocation gap is therefore not about issuer identity. It is about timing and propagation: where a revocation path exists, the PS can call the resource's revocation endpoint, but an agent may already have submitted a request using a token issued minutes before revocation was triggered. If the resource has not yet processed the revocation call, the request proceeds. What the protocol does not, and arguably cannot, define is what happens to work already in motion. An agent may hold valid auth tokens issued minutes before revocation. A downstream agent may have cached resource decisions. Queued operations may have already been submitted to external systems. Work that was authorized under the mission continues until those tokens expire, those caches invalidate, and those operations complete or fail on their own. The practical strength of revocation depends on: - the shortest-lived token in the chain - how aggressively each participating resource checks revocation - how many downstream hops already hold tokens or cached decisions - whether queued operations in external systems can be recalled **The mission series model: revocation needs stop semantics, not just revocation authority.** For high-consequence agent work, revocation authority is not the same as guaranteed stop. What matters is that when the PS terminates a mission, execution actually stops across the full delegation chain within a defined and operationally meaningful bound. That requires more than a revocation endpoint. It requires short token lifetimes, eager revocation checking at each hop, event-driven propagation to participating systems, and operational architecture built around the assumption that mission termination is a hard control signal rather than an advisory one. **The concrete failure mode.** A user discovers their agent is about to execute a bulk data export they did not authorize. They terminate the mission. The PS marks it terminated, calls the export service's revocation endpoint with the auth token's `jti`, and stops issuing new tokens. But the agent already submitted a request to the export service using a token issued two minutes before revocation was triggered. The request arrived at the export service before the PS's revocation call was processed. The export service queues the request, processes the revocation call, but the queued operation is already in flight. The data export proceeds. The PS did everything the protocol allows. Execution continued anyway. The control-plane revocation was correct and complete. The runtime stop failed. **Why AAuth makes this tradeoff.** Standardizing guaranteed stop semantics across arbitrary resources, caches, and execution environments is extremely hard. Different resources have different capabilities. Some can check revocation eagerly. Some cannot. Some queue work internally in ways that make recall difficult. Forcing the core protocol to guarantee instantaneous stop would require defining runtime architecture constraints that go well beyond what an authorization protocol should specify, and would exclude many legitimate resource implementations. Revocation authority belongs in the core protocol. Runtime stop guarantees belong in deployment profiles and operational architecture. The cost is real. In high-consequence environments such as financial operations, data access, and actions with external effects, the gap between "authority revoked" and "execution stopped" is exactly where harmful outcomes occur. Short-lived tokens and aggressive revocation checking can narrow the gap considerably, but closing it requires implementation discipline the protocol does not mandate. Deployments operating in high-stakes environments need to design for this explicitly. It will not be visible in the protocol spec alone. ## 4. Downstream attenuation is still too weak The published draft explicitly does not require downstream authorization to be a subset of upstream scopes. The design rationale is stated directly in the spec: a flight booking API that calls a payment processor needs the payment processor to charge a card, an operation orthogonal to the upstream scope. Formal subset rules would break legitimate cross-domain delegation chains. There is no mechanism to require attenuation and no vocabulary in the core protocol to express or verify it. A deployment profile could add formal attenuation constraints without contradicting the core protocol, but it would have to define scope vocabulary and subset semantics from scratch since the core provides no building blocks. That tradeoff is defensible in open cross-domain ecosystems. But from a mission governance standpoint, it is a significant gap in the delegation model. **The AAuth model: chain transparency without chain containment.** AAuth gives you provenance: the full delegation chain is visible. You can see that agent A authorized agent B, which authorized agent C, all correlated to the same mission. The audit record is complete. What the protocol does not guarantee is containment: that each downstream grant is actually a subset of the upstream authority. The PS evaluates each hop against the mission, but since the mission is prose, that evaluation is heuristic. A PS can assert that C's request is within the mission. It cannot prove it. **The mission series model: attenuation as a provable property of the authority chain.** In a system with a Mission Authority Model, attenuation is a formal property. Each downstream grant can be verified as a subset of the upstream authority envelope. If the parent grant permits resource class R, action A, within stage S, then the downstream grant must specify a subset of R, A, and S or be rejected. The evaluation is mechanical, not interpretive. That is not a theoretical nicety. It is what makes delegation chains trustworthy in adversarial or high-stakes environments. **The concrete failure mode.** An agent is authorized on a mission to "coordinate vendor onboarding for the Q3 contract." It delegates a sub-task to a procurement agent, which further delegates to a financial reconciliation agent. The PS evaluates each hop and issues tokens because each request sounds plausible relative to the mission description. The financial reconciliation agent ultimately performs actions that touch live payment systems, well outside what the user intended when they approved "vendor onboarding." Each individual PS evaluation was reasonable in isolation. The cumulative chain escaped the authority envelope. No participant can prove it was out-of-scope because there is no shared, machine-evaluable representation of what "vendor onboarding" actually authorizes. The provenance log records the chain perfectly. The audit record is clean. Nothing shows a containment violation because containment was never enforced. **Transparency is not the same as safety.** This is the critical distinction. Chain transparency is valuable: you can reconstruct exactly what happened and who authorized what. But observability after the fact is a different control from enforcement before the fact. Attenuation is a pre-execution guarantee: this request is within a provably bounded subset of the original authority. Provenance is a post-execution record: here is how the authorization chain evolved. Transparency tells you how authority evolved. Attenuation tells you whether it stayed inside a bounded envelope. Only one of them prevents harm before it occurs. **Why AAuth makes this tradeoff.** Formal attenuation rules that require each downstream scope to be a mathematical subset of upstream scopes work cleanly in closed, homogeneous systems. They break in cross-domain workflows where downstream resources have capability models that do not map onto upstream scope vocabularies. Forcing strict subset semantics would make the protocol unusable for many legitimate multi-domain workflows. The tradeoff favors flexibility and deployability now. The cost is that delegation chains cannot be formally verified, only asserted. In agentic systems where chains can be deep and execution can be long-running, that is not a theoretical risk. It is the expected failure pattern when scope creep occurs across a multi-hop delegation chain. The protocol will show you the chain clearly. It will not stop the chain from expanding beyond its intended bounds. ## 5. Cross-domain mission semantics are still local Gap #1 is about what the mission object provides within a single deployment for local enforcement. This gap is different: it is about what happens when two independently operated systems need to evaluate the same mission across a trust boundary without sharing the mission body. ### Mission correlation travels more easily than mission meaning The protocol now carries mission correlation through the chain: the `s256` hash and approver URL appear in resource tokens, auth tokens, and audit records. Any system that receives these can confirm "this action was correlated to mission M, approved by PS X." That is correlation. What it cannot do is enable a system to independently evaluate whether this action falls within what mission M permits. That requires the full mission body and a shared semantic model for interpreting it. **Two distinct levels of interoperability.** *Correlation interop*: two systems agree that a set of actions are associated with the same approved mission. The `s256` hash enables this. It is achievable today, across independent deployments, without sharing the mission body. *Enforcement interop*: two systems evaluate independently whether a given action is within the mission's authority and reach consistent conclusions. This requires either sharing the mission body (which creates disclosure problems) or sharing a machine-evaluable authority model derived from the mission that is safe to propagate. The draft achieves the first. It does not attempt the second. "Interoperable mission governance" as the protocol currently defines it means "interoperable mission correlation." Those are not the same thing. **The concrete failure mode.** An agent operates on a mission approved by org A's PS. Its execution requires resources hosted in org B's domain. Org B's AS federates with org A's PS and receives the mission hash and approver URL. Org B now must decide: does this mission permit the actions the agent is requesting against org B's resources? The AS can confirm a mission was approved. It cannot evaluate what the mission permits. Doing so would require fetching and interpreting the full mission body, which creates both a disclosure problem and an interpretation problem: org B's AS may read the same prose differently than org A's PS did. Org B's AS falls back to local policy. It might trust missions from PS X broadly, or require additional verification for sensitive resource classes. Two different deployments may apply entirely different local rules to the same federated mission. All of that variation is outside the protocol. **The privacy-enforcement tension.** The protocol's choice to share only the hash and approver URL rather than the full mission body is the right privacy decision. Mission bodies often contain sensitive business context. Forcing disclosure to every AS in a cross-domain workflow would be a serious privacy failure. But that constraint means richer cross-domain enforcement requires a way to convey mission authority without conveying mission content. That is precisely the problem a portable Mission Authority Model could solve: a compact, structured, privacy-safe artifact expressing what is permitted without revealing why, derivable from the approved mission and safe to share across trust boundaries. The protocol does not define one. `R3` can narrow part of this gap without eliminating it. Resources publish structured authorization vocabularies; auth tokens carry precise granted operations rather than bare scope strings. That gives independent systems a richer, less ambiguous surface for reasoning about what was actually authorized at each hop. It still does not tell them what the mission authorized in the first place. `R3` improves the precision of what authorization grants express and strengthens the substrate a mission-aware governance layer can use. A Mission Authority Model is still what would make mission containment portable. Correlation is interoperable now. Meaning is not. For deployments where cross-domain systems need to enforce against mission scope rather than simply correlate with it, that is the remaining gap. It is also the hardest one to close without solving gap #1 first. ### Federation does not remove relying-party trust policy The published draft makes real progress on cross-domain mechanics: - explicit PS-to-AS federation with trust establishment - pairwise user identifiers that limit cross-domain correlation - mission object propagation through token choreography - governance endpoints for cross-domain interaction and audit The remaining problem is not whether the federation flow works. It is that relying parties still have to decide for themselves what trust to place in federated mission context even if mission meaning becomes somewhat sharper. **What the federation model actually guarantees.** When the PS federates with an external AS, the AS receives the mission hash and approver URL. It can verify the signature chain, establish trust with the PS, and issue tokens correlated to the mission. The choreography is defined. The trust relationship is defined. What is not defined is what the AS is trusted to *accept* from the PS as sufficient mission context for its own resources. The AS sees a hash. It trusts the PS to have performed appropriate mission governance. It still has to decide, by local policy, whether that is enough for a given resource class, tenant, or risk level. This is where the federation story remains intentionally policy-heavy. Even if future profiles improve semantic portability, a relying-party AS still has to decide which PSes it trusts, for which resource classes, and under which operating conditions. The protocol can move more mission context and more structured request meaning. It still cannot remove the relying party's obligation to set trust policy at the boundary. **The concrete failure mode.** An enterprise PS approves a mission that includes "coordinate document review with external counsel." The agent operates across the trust boundary, submitting documents to a law firm's AS. The law firm's AS federates with the enterprise PS. The law firm's AS has its own data handling policies. It needs to decide: does this mission permit submission of documents marked "confidential"? Does it permit bulk submissions? Read access to the full document library, or only documents explicitly listed? The federated trust model tells the law firm's AS that *a* mission was approved. It does not convey what the mission permits in the law firm's context. The law firm has to choose: trust the enterprise PS entirely, make conservative local assumptions, or require out-of-band clarification. None of these is a governance answer. All of them leave the cross-domain policy question unresolved at the protocol level. If the enterprise and the law firm are both compliant AAuth implementations with different local policies, they will handle the same federated mission differently. The protocol does not and should not fully remove that discretion. Two deployments that trust each other at the identity layer may still make different authorization decisions at the policy layer. **The privacy-enforcement tension.** The protocol's choice to share only the hash and approver URL rather than the full mission body is the right privacy decision. Mission bodies contain sensitive business context. Disclosing them to every federated party would be a serious privacy failure. But this creates a hard constraint on what cross-domain enforcement can look like. Richer enforcement requires conveying more about mission scope without conveying mission content. That is the gap a portable Mission Authority Model could fill: a compact, structured, privacy-safe artifact expressing permitted scope, derivable from the approved mission yet safe to share across trust boundaries without disclosing the underlying business rationale. `R3` may help on the authorization side by making granted operations more precise: the relying-party AS sees structured grants rather than bare scope strings. It still does not decide what the relying party should trust the mission to authorize. **Why the current approach is defensible for now.** Defining a cross-domain semantic model before there is operational evidence of what mission semantics need to cross boundaries, and in what form, would likely produce the wrong model. The federation mechanics need to work first. Trust choreography is the harder near-term problem. Semantic portability can follow once deployments show what cross-domain enforcement actually requires in practice. The cost is that the current federation story is strong on identity correlation and trust choreography, and still dependent on local relying-party policy for enforcement. Deployments requiring richer cross-domain enforcement will need bilateral agreements, ecosystem-specific profiles, or custom projection mechanisms above the current core. That is the right place for them. But the work is not free, and nothing in the protocol spec will tell you where each relying party should draw its trust boundary. ## 6. Runtime alignment is still outside the protocol The PS provides meaningful request-time governance: - approve missions before execution begins - deny permissions when requests fall outside approved scope - log audit events for correlation and review - relay interaction when the agent needs clarification - refuse future token issuance when governance conditions change That is real and necessary. It is also only half the governance problem. **The distinction between request-time governance and runtime alignment.** Request-time governance answers the question: *is this request authorized?* It evaluates individual authorization decisions at the moment a token is requested. Runtime alignment answers a different question: *is the trajectory of this execution still aligned with the userโ€™s original intent?* It evaluates the cumulative pattern of agent behavior over time, across many individually authorized decisions, each of which may have been locally correct. These are not the same control. A protocol that solves the first does not automatically solve the second. The published AAuth draft solves the first well. It does not address the second. **The concrete failure mode.** An agent is authorized on a mission to "prepare a due diligence report on Acme Corp for our M&A team." The PS approves it. Each individual request is authorized: pulling filings, accessing analyst reports, querying internal deal databases. The audit log is clean. Midway through execution, the agent begins correlating information across the deal database and external news sources in ways the analyst did not anticipate. It drafts sections that mix confidential internal deal strategy with public market data in a form the user never sanctioned. Each step is within some plausible reading of the approved mission. The PS sees authorized requests and approves them. No individual authorization check fails. The cumulative execution has drifted meaningfully from user intent. The governance system has no visibility into this trajectory. This is what [Mission Shaping Is Not Enough](/notes/mission-shaping-is-not-enough/) describes: an agent can remain nominally inside mission scope while drifting semantically away from the userโ€™s actual intent. Approval at T=0 does not govern behavior at T=N. **What runtime alignment would actually require.** A runtime alignment layer needs capabilities the authorization protocol does not and should not define: - continuous observation of execution state, not just authorization events - semantic evaluation of accumulated agent behavior relative to approved intent - staged release gates that pause before high-consequence or irreversible actions - a feedback path from observation systems back into mission governance, so detected drift can trigger mission review or suspension **Why this is not a protocol design failure.** Standardizing runtime alignment inside the core AAuth protocol would be the wrong move. It would require the protocol to define agent behavioral semantics, execution monitoring, and semantic evaluation, all of which depend heavily on agent architecture, task domain, and risk model. That is not a protocol-layer problem. The gap here is one of architectural scope, not protocol design error. The protocol provides the authorization substrate and the governance hook: a PS with mission context that can refuse tokens and relay interaction. Runtime alignment needs to be built above that hook, treating it as a feedback point in the execution loop rather than just a record-keeping endpoint. That distinction matters for how deployments are designed. The protocol does not determine whether the PS is a passive logging mechanism or an active control point. A deployment that wires observation systems into the PS interaction endpoint and uses staged release gates before irreversible actions has far stronger runtime governance than one that treats mission approval as a one-time gate. The protocol does not make that choice for you. Deployments that assume it does will be surprised by the gap. # The Practical Takeaway The old takeaway was: > AAuth looks like a better substrate than OAuth, but it still appears to need a Mission-like governance object. The better takeaway now is: > AAuth now has a mission layer. The right question is no longer theoretical. It is operational. The architecture is now much closer to the one I have been arguing for: - agent identity and proof-of-possession at the protocol edge - a Person Server representing the legal person - mission proposal and approval before broader authorization unfolds - mission-aware resource and auth tokens - PS-to-AS federation across trust domains - governance endpoints for interaction, permission, and audit - a richer authorization description layer emerging at the resource boundary through R3 The remaining gaps are now easier to name precisely: - mission text is still not a full authority model, so correlation is more interoperable than containment - lifecycle and revocation are stronger in the control plane than in guaranteed runtime stop - attenuation across delegation chains is still too weak to make containment provable - cross-domain mission semantics and runtime alignment still need to be built above the current protocol layer The protocol family is no longer treating agent identity and token choreography as the whole answer. It is now building around a mission-aware governance layer and a richer authorization layer at the resource boundary, even if the deeper authority-model problem is still not fully solved. The published draft standardizes mission coordination and correlation. `R3` adds more precise request meaning at the resource boundary. Together they strengthen the substrate for governance without yet standardizing shared mission containment. That is not a reason to dismiss the work. It is a reason to position it correctly. This is foundational work for an agent-native world because it moves the protocol stack toward mission-aware governance without overreaching into every harder problem at once. The published protocol gives Mission a first-class governance role. `R3` makes resource requests more semantically legible. That combination materially improves the substrate even before a full Mission Authority Model exists. The stack is now much stronger on mission correlation and governance hooks than it was before. It still does not standardize portable mission containment. That is the real remaining gap, and the right place for the next layer of work to explore. --- # Sources - [draft-hardt-aauth-protocol-01 on Datatracker](https://datatracker.ietf.org/doc/draft-hardt-aauth-protocol/) - [AAuth Rich Resource Requests (R3) draft dated April 13, 2026](https://dickhardt.github.io/AAuth/draft-hardt-aauth-r3.html) - [Mission Architecture on AAuth](/notes/mission-architecture-on-aauth/) - [Open-World OAuth Still Needs Mission Shaping](/notes/open-world-oauth-still-needs-mission-shaping/) - [The Mission Shaping Problem](/notes/the-mission-shaping-problem/) - [Mission Shaping Is Not Enough](/notes/mission-shaping-is-not-enough/) - [Why Mission-Bound OAuth Might Be the Wrong Answer](/notes/why-mission-bound-oauth-might-be-the-wrong-answer/) --- # ID-JAG Beyond the Enterprise IdP Canonical URL: https://notes.karlmcguinness.com/notes/id-jag-beyond-the-enterprise-idp/ Markdown URL: https://notes.karlmcguinness.com/notes/id-jag-beyond-the-enterprise-idp.md [ID-JAG](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/), the Identity Assertion JWT Authorization Grant, is a draft OAuth specification for carrying identity assertions across OAuth authorization server boundaries without requiring interactive authorization at each hop. A user authenticates once. The client typically exchanges the resulting identity assertion via [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange into an ID-JAG. The ID-JAG is then presented to a target authorization server using [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523) as the authorization grant, producing an access token for that service without a redirect, a consent screen, or a second login. This same general pattern is also often discussed under the name `XAA`, for Cross-App Access. In this post I use `ID-JAG` for the protocol term and `XAA` only as a shorthand label readers may already recognize. I am one of the authors of the specification, so I want to be open about where I am describing the current draft and where I am stretching into a broader architectural argument. That distinction matters here because the draft itself is already moving: the newer editor's copy adds a product and CIAM-shaped example, [Customer Identity for Developers](https://drafts.oauth.net/oauth-identity-assertion-authz-grant/draft-ietf-oauth-identity-assertion-authz-grant.html#name-customer-identity-for-devel). By `CIAM` here I mean customer identity and access management platforms such as Auth0, WorkOS, Stytch, Descope, and similar product-identity layers. That does not settle the boundary by itself, but it is a helpful sign that the older "Enterprise IdP" framing is already being tested against a wider set of deployment realities. The argument in this post is narrower than "ID-JAG solves cross-domain authorization." It is simply that "Enterprise IdP" is too narrow a frame for the trust pattern. In the current draft, the issuer that matters is the IdP the downstream authorization server already trusts for SSO and subject resolution. The broader point is that this immediate-IdP role may be held by a workforce IdP, a CIAM platform, or an internal platform IdP depending on the deployment. That framing matters now because product ecosystems and agentic systems are increasingly separating workforce authentication, product-local identity, and downstream authorization into different layers. The older habit of treating the top-level workforce IdP as the only IdP that matters no longer fits how many systems are actually built. # What ID-JAG Changes In the common user-delegated OAuth pattern, the client sends the user to the authorization server for an authorization request, the user authenticates and approves the request there, and the authorization server issues a code or other grant under its own policy. In the ID-JAG draft, the downstream authorization server for this hop is the **Resource Authorization Server (RAS)**. ID-JAG makes a narrower move. It lets a Resource Authorization Server accept an identity assertion issued by the IdP the RAS already trusts for SSO and subject resolution as the OAuth authorization grant, instead of forcing the client to run another direct interactive authorization flow there. The IdP becomes the assertion issuer the RAS relies on for this hop. The RAS still decides whether to honor the assertion, what scopes to allow, and what token to mint. That matters because it avoids implying a fundamental OAuth role change. ID-JAG does not redefine the underlying ownership model of the protected resource. In some deployments the effective resource owner is an individual user; in others it is a tenant- or organization-administered account model. The RAS still issues tokens under its own policy, and the resource server still enforces access to protected resources. What changes is the grant path: the RAS is willing to treat a trusted IdP-issued identity assertion as sufficient input for token issuance. When that works well, some approval and policy work can be centralized at the IdP or its surrounding governance layer, but the downstream service does not surrender final control. The IdP mediates the cross-domain hop. The RAS still applies local policy. What does change is where user consent and authorization visibility live. In interactive OAuth, the user sees a consent screen at each service. ID-JAG removes that interaction. The governance equivalent is pre-authorized scopes defined at the IdP or in the RAS's client registration, or admin consent granted at the organizational level. The user's visibility into which downstream services their identity assertion can reach is a policy question each deployment has to answer explicitly, through IdP-level scope governance, admin consent flows, or session-bound scope limits, rather than through interactive consent at each service boundary. That is an operational consequence worth saying plainly. If a deployment adopts ID-JAG, it is also choosing to move visibility and approval away from the downstream service's consent screen and into some combination of IdP policy, client registration, tenant admin approval, or other governance controls. If those controls are weak or opaque, the user may lose visibility even if the protocol mechanics are sound. That is also why ID-JAG should not be read as creating a new concentration of power at the IdP. From a threat-model perspective, an IdP that is already trusted for SSO can often already approximate a similar downstream access outcome indirectly: silently sign the user in, drive the front-channel steps of an OAuth request without the user present, and orchestrate the browser interactions needed for the client to obtain a code through equivalent choreography. In other words, an SSO-trusted IdP may already be able to simulate the consent path without the RAS changing its protocol behavior. That is not desirable, and it is not protocol-equivalent to ID-JAG. But it is why the underlying trust question is already there. ID-JAG does not create that trust position. It makes the cross-domain grant path explicit, typed, and reviewable instead of relying on brittle front-channel mechanics to approximate a similar outcome operationally. # The Constraint Is the Trust Relationship, Not "Enterprise" ID-JAG reads very naturally as an Enterprise IdP story. An Enterprise IdP authenticates employees. Enterprise-managed services trust that IdP and often pre-authorize certain clients and scopes. So ID-JAG lets employees move across those services without extra login prompts. That use case is real, familiar, and valuable. But the constraint is not just "enterprise." The constraint is the issuer, client, and policy trust relationship. The mechanism works because the RAS has established trust with the issuer for identity assertions and has policy for the client and requested access. In the enterprise examples in the draft, that includes more than generic SSO trust: the client and RAS are configured for this pattern, and the client has permission to act for the target service with defined scopes. That is the deployment shape the current draft directly specifies. What "configured for this pattern" means in practice: the RAS has already established how it recognizes and validates assertions from the issuer it trusts for SSO and subject resolution, and maps that issuer to permitted clients and scopes. In OpenID Connect deployments that usually means issuer metadata and JWKS configuration; in SAML deployments it means the equivalent federation metadata and key trust. ID-JAG adds the grant-type and claim-processing rules on top of that existing trust relationship. That incremental adoption path was one of the primary goals of ID-JAG. The deployment work is issuer registration, client-to-grant-type binding, and scope policy. It is not new trust infrastructure from scratch. The Resource Authorization Server does not need a new access-token format or a new token-issuance model; it is still issuing its own access tokens under its own policy. The Resource Server does not need to change which authorization server it trusts or what token claims it relies on at runtime. The main change is at the grant-acquisition boundary: which upstream issuer the Resource Authorization Server is willing to accept as input for token issuance. From an implementation perspective, a resource authorization server can trust more than one issuer. There is no protocol constraint that says one tenant or deployment context must map to exactly one IdP. The cost is complexity: once multiple issuers are accepted, the deployment has to handle issuer routing, account linking, subject normalization, and policy mapping carefully. The constraint is operational clarity, not single-issuer exclusivity. The broader architectural point is a little different. The protocol does not inherently require the issuer to be the top-level workforce IdP. It requires the issuer to be the IdP the downstream authorization server already trusts for SSO and subject resolution. In some environments, that will still be the enterprise workforce IdP. In others, a CIAM platform or internal platform IdP may federate upstream to the workforce IdP for employee login, but still be the IdP that downstream systems trust directly. In that shape, the chained workforce IdP is upstream authentication infrastructure, while the CIAM or platform IdP is the issuer that actually satisfies the ID-JAG trust condition for those downstream services. That is exactly why the specification is grounded in identity assertions rather than arbitrary JWT claim sets. The issuer has a defined identity role relative to the RAS. The word "enterprise" describes one deployment context where that relationship is common. It does not define the limits of the pattern. # Four Deployment Contexts ## Enterprise Workforce This is the canonical case. The Enterprise IdP is authoritative for employee identity, organizational policy, device posture, and the access rules the employer has defined. Services and internal tools accept the Enterprise IdP for SSO, and the relevant clients and authorization servers are configured for ID-JAG. Employees move across authorized services without interactive re-authorization at each boundary. This is also the most operationally mature context for ID-JAG because the infrastructure already exists: SSO trust is established, policy governance is in place, and authorization servers are already configured to accept the IdP. ID-JAG is an extension of what is already there. ## CIAM and Product Platforms A CIAM platform or product suite has its own identity graph. Users join through self-serve signup, enterprise federation, social login, or direct invitation. The platform is the authoritative issuer for those identities, regardless of which upstream directory any individual user came from. It manages the tenant relationships, the permission model, and the lifecycle of access across the product's surfaces. That identity governance authority is the same kind of authority an Enterprise IdP holds for its own subjects. When the platform acts as an IdP and downstream services within the ecosystem already trust it directly for SSO and subject resolution, the same immediate-IdP logic applies. A common shape is federation chaining: the user may authenticate upstream with an enterprise workforce IdP, but the CIAM platform is still the IdP that downstream product services trust directly for SSO and subject resolution. In that case, the CIAM platform, not the upstream workforce IdP, is the issuer that matters for ID-JAG at that boundary. That trust relationship also means the CIAM platform has to own subject linking carefully. If the upstream workforce IdP uses pairwise subject identifiers or the product has to normalize identities across multiple upstream directories, the CIAM platform must map those upstream identities into the product-local subject identifier the downstream authorization server expects. That mapping burden is part of what it means for the product IdP to be the immediate IdP at that boundary. This covers the full scope of identities a B2B SaaS product actually serves: workforce users who arrive via enterprise federation, users who joined before enterprise federation existed, external collaborators, partners, API developers, and customers who are themselves end-users rather than employees. The product governs all of these. The Enterprise IdP governs the workforce subset. Both can participate as issuers for the identities they are authoritative over where the downstream RAS already trusts them for SSO and subject resolution. None of that removes the RAS's sovereignty. The product IdP being the immediate IdP does not obligate the downstream authorization server to accept every assertion it issues. The RAS still decides whether to honor, narrow, or reject the grant under its own policy. ```mermaid sequenceDiagram actor U as User participant EIDP as enterprise-idp.example.com participant PIDP as product-idp.saas.example participant C as Client participant RAS as saas-component.example.net C->>PIDP: Start authentication PIDP->>EIDP: Federated auth request as client U->>EIDP: Authenticate with workforce identity EIDP->>PIDP: Federated login assertion PIDP->>C: Authentication result in product domain C->>PIDP: RFC 8693 token exchange (subject_token = PIDP ID token) PIDP->>C: ID-JAG C->>RAS: RFC 7523 JWT bearer grant RAS->>C: Access token Note over PIDP,RAS: PIDP is the immediate IdP/AS trusted by the downstream RAS Note over EIDP,PIDP: EIDP is the upstream workforce authentication source ``` Two concrete product shapes make that immediate-IdP distinction especially clear. **Agentic workflows.** An enterprise employee may launch the workflow, but the SaaS platform still has to govern product-local agent permissions, approval rules, runtime duration, tool access, and audit across the user-to-agent-to-tool chain. The workforce IdP can authenticate the employee. Where the downstream product services already trust the product or CIAM IdP directly for SSO and subject resolution, that product IdP is often the right system to issue the identity assertion they consume, because it owns the tenant model and product-local account context those services use as inputs to their own authorization decisions. **Admin and support elevation.** A workforce IdP can prove who the support engineer is, but it usually does not own the ticket context, tenant scoping, break-glass policy, approval window, or product-local controls that determine what elevated support access should mean. Where the downstream product services already rely on the product IdP for SSO and subject resolution, that product IdP can issue a product-domain identity assertion that carries the right local subject and tenant context into the downstream token request, leaving the downstream services to enforce support access under their own bounded workflow rules rather than a generic employee entitlement. ## Platform and Internal Service Identity A platform may operate its own IdP as the trust anchor for a set of internal gateways, services, or API surfaces. Those services are configured to trust the platform IdP for authentication, and where the Resource Authorization Servers also accept that issuer for ID-JAG, the same trust pattern can remove per-service interactive flows. Here too, the platform IdP may itself federate upstream to a workforce IdP while remaining the immediate IdP the downstream systems already trust for SSO and subject resolution. This is the architectural shape for microservice architectures, API gateway patterns, and internal developer platforms where the platform IdP governs service-to-service identity and access. The key point is that the downstream systems trust the platform IdP directly. The same pattern also appears in gateway bridge designs, where a platform gateway sits between upstream enterprise identity and downstream product or partner APIs and has to translate that identity into product-local tenant context and downstream audience-specific assertions. ## Personal and Developer Identity Developer toolchains, package registries, cloud provider CLIs, and similar surfaces follow the same trust logic. A developer authenticates to a central platform, such as a cloud identity provider, source-code hosting platform, or internal developer portal, and that platform becomes the immediate IdP that downstream tooling and registries already trust for SSO and subject resolution. The same ID-JAG trust pattern applies without requiring enterprise infrastructure: what matters is the established SSO trust relationship between that developer identity platform and the downstream authorization servers, not whether the platform is backed by an enterprise workforce IdP. A concrete shape: a developer authenticates to a source-code hosting platform. A CI pipeline needs to push an artifact to a registry that already accepts that platform as its SSO IdP. The pipeline exchanges the platform-issued identity token into an ID-JAG via RFC 8693, then presents it as the authorization grant to the registry's token endpoint via RFC 7523. The registry issues a scoped access token for the push without requiring an interactive redirect or a separate developer credential. The hosting platform is the immediate IdP because the registry already trusts it for SSO and developer subject resolution, the same relationship that backs the developer's interactive login. This is the context that most directly demonstrates the pattern is not bounded by enterprise deployment. The developer case satisfies the same trust constraint (a trusted issuer, a configured client, established policy) while the identity source and governance model are entirely different. # Agentic Systems Agents make the issuer model harder to compress because three different identity questions appear at once: who the employee is, what product-local account and tenant context the downstream services recognize, and what software is actually executing. The workforce IdP may authenticate the employee. The product or platform IdP may still be the identity system that downstream services trust directly for subject and tenant context. A workload identity layer may separately prove the executing software. That separation matters because downstream services rarely authorize against "workforce identity" in the abstract. They authorize against the local account, tenant, and product relationship they understand, while other parts of the stack may separately care about the executing workload. The useful IAM move is to keep those roles distinct instead of pretending one issuer is authoritative for all of them. Agents also make the cross-domain boundary much more obvious. A workflow that starts inside one SaaS product often does not stay there: it may need to read from a ticketing system, update a CRM record, open a case in an ITSM tool, or call other enterprise APIs that live under different authorization servers. This is where the `Cross-App Access` label fits especially well. Once an agent has to move across application boundaries, it needs a shared trust anchor those downstream systems already recognize. In many enterprise deployments that shared trust anchor is the Enterprise IdP, even if a product or platform IdP still governs local tenant context inside its own trust domain. A related question in agentic and platform architectures is whether ID-JAG chains across multiple hops. The recommendation is that deployments treat each trust boundary as requiring its own ID-JAG from the immediate IdP trusted at that boundary, rather than propagating a single assertion through the whole stack. In a three-tier architecture where a workforce IdP federates into a CIAM platform that in turn is trusted by downstream microservices, the CIAM platform issues an ID-JAG for the downstream hop. That ID-JAG is scoped to the trust relationship between the CIAM platform and those services; it does not carry the upstream workforce assertion forward as the operative grant. Each boundary has its own issuer, its own trust relationship, and its own grant. That is the useful distinction for this post. The current ID-JAG draft is narrower than the full agent stack: it is an end-user identity assertion from the IdP the RAS already trusts for SSO and subject resolution. But that still means the issuer that matters at a given boundary may not be the top-level workforce IdP. In many product deployments, the CIAM or internal platform IdP sits downstream of workforce federation and is still the right ID-JAG issuer for the services inside its own trust domain, because those services already trust it directly at the relying-party boundary, even though it is not the system that originally authenticated the employee and not the system that proves the executing software. # Why Not Just Token Exchange and JWT Grants? RFC 7523 defines a generic JWT bearer authorization grant profile. It does not assume the issuer is an identity provider, but it also does not eliminate trust requirements. The RAS still has to decide which issuers it accepts, how it validates claims, and what additional policy applies. If you combine [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange with [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523), you can build something that looks superficially similar to ID-JAG. The problem is that the generic stack leaves too much of the trust model, payload shape, and security behavior to local convention. The reason that matters to this post is simple: ID-JAG is not just another way to package the same flow. It is a profile that narrows several places where a hand-rolled composition is easy to get wrong. RFC 7523 is not missing trust altogether, and careful deployments do configure issuers they trust. What it does not provide is a standard IdP role, a defined payload profile, or specified security behavior for this cross-domain trust pattern. - It narrows the trust model: the issuer is the IdP the RAS already trusts for SSO and subject resolution, not an arbitrary JWT signer. That established SSO relationship narrows subject mapping work, though it does not eliminate it: in pairwise-pseudonymous or multi-registration deployments the IdP still has to ensure the `sub` in the ID-JAG is the subject identifier the RAS expects for that user. - It narrows the payload semantics: audience, `client_id`, tenant context, and subject alignment are all more explicit than in a generic composition. - It narrows the security behavior: sender-constraining continuity, resource and scope handling, and refresh behavior are profiled instead of left to local convention. So the value of ID-JAG is not that generic JWT grants and token exchange are incapable of expressing a similar flow. The value is that ID-JAG turns a hand-rolled composition into a recognizable profile with tighter trust, clearer claim semantics, and fewer security ambiguities. # The Claim Worth Making The constraint in ID-JAG is not enterprise branding. It is the existence of an issuer, client, and policy relationship under which the RAS is willing to accept an end-user identity assertion as a grant. In the current draft, that issuer is the IdP the RAS already trusts for SSO and subject resolution. That can be an enterprise workforce IdP, but it can also be a CIAM platform or an internal service IdP when those systems are the immediate IdPs for the downstream services in question. That constraint is a feature, not a limitation. It gives the protocol a governance anchor. The RAS is not evaluating arbitrary claims from unknown issuers. It is evaluating assertions from an issuer it has already decided to trust for this category of grant, while still applying its own local policy. Enterprise IdPs are the right issuers for workforce identity and enterprise-managed policy. Product or platform IdPs may be the right issuers for the local identities and relationships they govern inside their own ecosystems, including cases where they federate upstream to a workforce IdP but remain the direct SSO authority for downstream services. Framing ID-JAG as only a top-level workforce IdP extension narrows the pattern unnecessarily. Framing it as a generic multi-issuer substrate goes too far the other direction. The stronger claim is that the pattern can extend beyond classic enterprise deployments wherever the downstream authorization server already trusts that issuer as its SSO IdP and is configured for the grant. Put differently: the immediate IdP trusted by the RAS may not be the top-level workforce IdP. In many product and platform deployments, that immediate IdP is the CIAM or platform identity layer that federates upstream workforce identity but remains authoritative for the downstream trust boundary. If CIAM, platform identity, or developer toolchain deployments are part of your use case for this pattern, now is the time to raise them in the working group. The draft is still moving and the text is still being shaped. The more concrete deployment examples the working group has on the table, the better the specification can reflect the full range of contexts where this trust pattern actually applies. If you think that change improves the draft, weigh in on [ID-JAG PR #82](https://github.com/oauth-wg/oauth-identity-assertion-authz-grant/pull/82). Concrete support or counterarguments there are more useful than vague agreement. --- # Open-World OAuth Still Needs Mission Shaping Canonical URL: https://notes.karlmcguinness.com/notes/open-world-oauth-still-needs-mission-shaping/ Markdown URL: https://notes.karlmcguinness.com/notes/open-world-oauth-still-needs-mission-shaping.md [Part 1](/notes/oauth-for-open-world-ecosystems/) focused on OAuth's substrate problem: agents discover protected resources at runtime, which inverts the closed-world assumption that clients, authorization servers, and resource servers were all pre-configured to know each other. [Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728), [OAuth Client ID Metadata Document](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/), [sender-constrained tokens](https://datatracker.ietf.org/doc/html/rfc9449), [metadata integrity](/notes/oauth-for-open-world-ecosystems/#-metadata-integrity-under-adversarial-conditions), and [first-contact trust](/notes/oauth-for-open-world-ecosystems/#-first-contact-trust-is-bilateral) all matter because the protocol base has to work before anything higher-level can be trusted. A working substrate is not the same thing as a complete authorization model for agents. Even after discovery, resource binding, and first-contact trust all work, a generic agent still faces a harder problem: how does it turn approved task intent into correctly bounded authorization requests across unfamiliar tools, resources, and domains? That is where open-world OAuth runs into the [Mission shaping](/series/mission-shaping/) problem. In this model, a [Mission](/notes/the-mission-shaping-problem/) is the durable authority object compiled from approved intent, bounded across delegation, and governed through the lifecycle of the task. # ๐Ÿค The Handoff From Protocol To Mission Imagine the example from Part 1: an agent is helping a salesperson prepare an account-renewal brief. The agent discovers a CRM [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) tool at runtime. [Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728) tells it how the CRM API is protected. The Authorization Server (AS) returns a token whose effective `resource` binding is confirmed ([OAuth 2.0 Resource Parameter in Access Token Response](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-resource-token-resp/), as discussed in [Part 1](/notes/oauth-for-open-world-ecosystems/)). The client has enough metadata to evaluate whether the CRM AS should be trusted. The CRM resource server has enough policy basis to accept the issuer. That is a much better world than today's open-world OAuth baseline. But the agent then discovers that it needs billing history from another domain. The protocol questions return: - can the agent discover the billing resource's authorization requirements - can it get a token with confirmed resource binding - can each side evaluate first-contact trust - can delegation cross the boundary safely And even if every protocol step succeeds, the Mission question remains: - is billing-history access still inside the user's approved renewal-preparation task - is the requested authority a narrow derivation or a material expansion - should the user see a new approval prompt - should the original Mission be expanded, forked, or rejected - what happens to already-derived authority if the Mission is later narrowed or revoked OAuth can expose better signals. It cannot, by itself, decide whether the agent is still operating inside the purpose the user approved. # โ›“๏ธ Delegation and Authorization Chains Across Trust Domains Multi-hop delegation is still part of the open-world trust problem. Once discovery happens at runtime, delegation chains can reach AS boundaries that were not pre-configured either. The first-contact problem reappears, now applied to delegated authority rather than to client and resource discovery alone. This is where Mission starts to matter. The question is not only whether one token can be exchanged for another. It is whether the delegated act still remains inside the purpose the user approved. [OAuth 2.0 Token Exchange](https://datatracker.ietf.org/doc/html/rfc8693) ([RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693)) provides a framework commonly used for delegation within a trust domain where the involved ASes have a pre-existing relationship. The `act` claim records who is acting on whose behalf, but even within a single domain the claim is not uniformly profiled: two standards-compliant implementations can disagree about delegation semantics when a token crosses a trust boundary (see [Standardize `act` Across Assertion Grants and JWT Access Tokens](/notes/standardize-act-claim-across-assertion-grants-and-jwt-access-tokens/)). Multi-hop chains that cross AS boundaries with no prior relationship between them are not well specified. The specific problems are operational, not abstract: - how does a downstream AS validate that the delegation chain it is seeing is authentic - how does it determine that the upstream AS that issued the parent token is trustworthy enough to vouch for delegation - how does it enforce that each hop properly attenuated rather than expanded the delegated authority - how does a generic client discover whether a target AS supports token exchange, chaining, or some narrower delegation profile at all Three active drafts each address a different layer of this problem. [OAuth Identity and Authorization Chaining Across Domains](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-chaining/) addresses the cross-AS trust layer: how an AS establishes trust with another AS based on discovered metadata and how delegation claims propagate across AS boundaries. [Transaction Tokens](https://datatracker.ietf.org/doc/draft-ietf-oauth-transaction-tokens/) address the intra-domain context layer: within a trust domain, how caller context propagates through chains of service or agent calls so that each downstream service sees who initiated the chain and under what authority. [Identity Assertion JWT Authorization Grant](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/) (ID-JAG) addresses a narrower downstream grant-friction problem: a user authenticates once with an Identity Provider (IdP), the IdP issues an identity assertion, and the client presents that assertion to a target AS as an [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523) JWT Bearer authorization grant to obtain access without a full interactive authorization step in every coordinated downstream domain. Taken together, these drafts show that the delegation problem is visible and active. They do not yet provide a settled end-to-end answer for open-world, cross-AS delegation chains. A settled answer would require at least: - a standard way for ASes to publish support for specific token exchange and chaining profiles - a trust framework that lets downstream ASes evaluate whether an upstream AS is authorized to vouch for delegation in a given context - chain-level attenuation guarantees that are verifiable at each hop rather than enforceable only by convention within a single trust domain - stronger subject and actor continuity so downstream parties can tell not just who is acting now, but how that actor relates to the original approved principal For Mission-aware systems, actor continuity is not just provenance metadata. It is part of Mission state: the system needs to know whether the actor executing the next derived action is still the actor, or delegated actor, the Mission authorized. And even if discovery, trust establishment, and delegation worked perfectly, a generic agent would still face a harder question: how does it know what authorization request it should form in the first place? # ๐Ÿงฉ Task Intent and Tool Authorization Semantics Are Still Missing A larger open gap runs across all of these layers: OAuth still does not give generic agent systems a reliable way to move from task intent to concrete authorization semantics. That is the problem the [Mission Shaping](https://notes.karlmcguinness.com/series/mission-shaping/) series is about. Enforcement systems do not authorize intent. They authorize operations on resources under specific conditions. A user intent such as "prepare the renewal notes for these accounts" is not an authorization request. Something has to translate the first into the second, and open-world OAuth exposes exactly where that translation is missing. OAuth scopes are intentionally opaque strings. They carry no machine-readable semantics about what operations they represent, what resources they govern, or how they compose. That opacity worked in closed-world deployments where developers read the documentation and hard-coded scope values. It does not work for a generic agent encountering an unfamiliar domain at runtime. Three specific gaps make the problem concrete. First, the client cannot understand the authorization semantics of an unfamiliar domain from scope strings alone. It sees opaque tokens, not a machine-readable mapping from tool intent to domain authority. This is where resource-declared semantics, richer `authorization_details` profiles (structured authorization objects defined by [RFC 9396](https://datatracker.ietf.org/doc/html/rfc9396) for expressing richer authorization requests beyond flat scope strings), or equivalent machine-readable domain vocabularies become important. Second, the consent path does not scale. Today's consent path relies on `WWW-Authenticate` challenges and scope-based authorization requests. That allows incremental improvement, but it often puts a human back in the loop every time the agent encounters a new resource or tool surface. In the CRM-to-billing scenario, that can turn one coherent task into multiple consent interruptions or partial failures. This is partly a UX problem, but it is also a protocol-shaping problem because the ecosystem still lacks standard ways to bundle, reuse, or reason over related authorization requests as one task unfolds. Third, delegation capabilities are not discoverable enough for generic clients. In principle, a parent agent should be able to request a narrowed token for a sub-agent. In practice, there is usually no standard way for the AS to publish that such an operation is supported, what token exchange profile it expects, whether chaining or attenuation constraints apply, or how a client should map its current intent into the `scope` values or `authorization_details` needed for the derived request. Even when token exchange exists, the agent often does not know what it should ask for. # ๐Ÿ“ RAR, R3, and Where Semantics Should Live [Rich Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9396) (RAR, [RFC 9396](https://datatracker.ietf.org/doc/html/rfc9396)) and [RAR metadata](https://datatracker.ietf.org/doc/draft-zehavi-oauth-rar-metadata/) are relevant because they expose schemas for `authorization_details` types and give ASes a way to advertise some of the structured authorization language they understand. That is useful progress. It turns at least part of the AS contract into discoverable metadata rather than documentation. But it still does not solve the full task-to-authorization problem for open-world agents. The client may know the shape of a valid `authorization_details` object and still have no reliable way to derive the right object from a newly discovered tool call or from a higher-level task description. [AAuth R3](https://dickhardt.github.io/AAuth/draft-hardt-aauth-r3.html) (editor's copy, accessed April 7, 2026) is interesting here because it pushes on the other side of the semantics problem. Instead of asking the client to invent the right authorization object, R3 lets resources publish structured, content-addressed authorization definitions in vocabularies agents already understand, including MCP, OpenAPI, and gRPC. These two approaches reflect different assumptions about where authorization semantics should live. RFC 9396 RAR is client-declared: the client constructs `authorization_details` and asserts them in the request. R3 is resource-declared: the resource publishes structured authorization definitions in vocabularies agents already understand. That distinction matters for generic agents. An agent encountering an unfamiliar resource has no reliable basis for constructing a correct RAR object from scratch. R3's resource-declared model is a direct attempt to shift that burden. How RAR and resource-declared approaches compose will shape what the authorization semantics layer actually looks like for open-world agent systems. > Resource semantics are still not Mission semantics. Discovery tells the client where to go. Binding tells it what token it got. Trust helps it decide whom to trust. R3-style resource definitions help the agent understand what a resource exposes. None of those, by themselves, tell a generic agent whether the newly discovered action is inside the purpose the user approved. # ๐Ÿ”„ Consent Continuity and Mission Lifecycle The task-intent problem has a visibility problem layered on top of it. Even if an agent could perfectly map intent to authorization requests, the user would still have no standard way to see what tokens were acquired during execution, what resources were accessed under their authorization, or whether the agent's runtime behavior remained within the scope of what was originally approved. The gap is not just semantic. It is auditability and control. The gap spans both client and AS. The AS has no standard mechanism for evaluating whether a runtime token request for a newly discovered resource remains within the intent of the user's original grant. The client has no standard mechanism for notifying the user when those acquisitions expand the effective authorization surface. That leaves an unresolved model question: in an open world, what keeps user approval meaningful? In the CRM-to-billing scenario, broad ex ante approval would let the agent keep expanding across systems without showing the user what changed. Step-up on every newly discovered resource would preserve visibility but destroy autonomy. Some form of policy-mediated expansion is the most plausible direction, but the protocol building blocks for it are still incomplete. Revocation and termination sit inside the same gap. If a mission is narrowed, paused, revoked, or expires mid-execution, the ecosystem lacks a standard way to ensure that already-derived authority, cached tokens, and downstream delegated actions collapse with it coherently. Standard token revocation ([RFC 7009](https://datatracker.ietf.org/doc/html/rfc7009)) requires the client to know which AS to contact. When ASes were discovered dynamically and client state may be ephemeral, that assumption does not hold reliably. In the renewal example, if the account owner cancels the renewal brief after the CRM token has been used to derive billing access, the system needs a way to terminate the billing-side authority as part of the same Mission lifecycle rather than waiting for an unrelated token expiry. That is where protocol design ends and governance begins. OAuth can expose better signals, boundaries, and artifacts. It cannot by itself answer whether an agent is still operating within the bounds of what was originally approved, nor can it decide where that policy should live operationally: at the AS, the RS, the orchestrator, or an external policy engine. That is the question the [Mission Shaping](https://notes.karlmcguinness.com/series/mission-shaping/) and [Mission-Bound OAuth](https://notes.karlmcguinness.com/series/mission-bound-oauth/) series address: not how a client discovers and acquires the right token, but how approved intent becomes a durable authority that stays in force across every derivation step. # ๐Ÿ—๏ธ Open-World OAuth Needs a Mission Layer Improving the open-world OAuth substrate is necessary and worth the investment. [Part 1](/notes/oauth-for-open-world-ecosystems/) identified targeted, fixable gaps ([resource identifier matching](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-rfc9728bis/), [resource binding confirmation](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-resource-token-resp/)) and deeper trust-framework work around [metadata integrity](/notes/oauth-for-open-world-ecosystems/#-metadata-integrity-under-adversarial-conditions) and [first-contact trust](/notes/oauth-for-open-world-ecosystems/#-first-contact-trust-is-bilateral). Those improvements matter. But a better substrate does not eliminate the need for a Mission layer. Mission shaping is not just better token exchange or richer request syntax. The unresolved problem is not only how authority is conveyed. It is how runtime action stays aligned with approved purpose as the agent discovers new tools, crosses domains, delegates work, asks for new authority, and eventually terminates the task. [AAuth](https://dickhardt.github.io/AAuth/draft-hardt-aauth-protocol.html) (editor's copy, accessed April 7, 2026) is one clear signal of this convergence. It redesigns authorization choreography around open-world assumptions and introduces explicit Mission concepts into the protocol conversation. Other active drafts are pointing in the same direction. [Policy and Lifecycle Extensions for OAuth Rich Authorization Requests](https://datatracker.ietf.org/doc/draft-chen-oauth-rar-agent-extensions/) explores policy context and task-bound authorization lifetime. [OAuth 2.0 Scope Aggregation for Multi-Step AI Agent Workflows](https://datatracker.ietf.org/doc/draft-jia-oauth-scope-aggregation/) addresses repeated-consent pressure in multi-step workflows. The [Agent Authorization Profile for OAuth 2.0](https://datatracker.ietf.org/doc/draft-aap-oauth-profile/) takes on task context, operational constraints, delegation chains, and human oversight as explicit protocol concerns. That convergence is encouraging. The distinction that remains is between protocol concepts that make agent authorization more explicit and Mission shaping as durable bounded authority: compiled from approved intent, bounded across delegation, governed through the lifecycle of the task, and terminated coherently when the business reason ends. It sits above protocol artifacts and answers not just whether a token is valid, but whether the execution is still authorized. Open-world OAuth is the substrate problem. Mission shaping is the authority-governance problem above it. Agent authorization needs both layers to hold. --- # OAuth for Open-World Ecosystems Canonical URL: https://notes.karlmcguinness.com/notes/oauth-for-open-world-ecosystems/ Markdown URL: https://notes.karlmcguinness.com/notes/oauth-for-open-world-ecosystems.md OAuth was not designed for the world agents operate in. That is not a criticism. It is why OAuth succeeded. OAuth became mature because its deployment model was constrained: clients, authorization servers, and resource servers were configured to know each other before runtime. That made the threat model legible and the security surface analyzable. Agents invert that assumption. They discover tools and protected resources at runtime, encountering authorization servers and resource servers they were never configured to know. That is a different deployment model, and it requires different protocol primitives. [Protected Resource Metadata (PRM)](https://datatracker.ietf.org/doc/html/rfc9728), [OAuth Client ID Metadata Document (CIMD)](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/), and related drafts are starting to close that gap. But the transition is incomplete. This post focuses on that specific problem: what it takes for OAuth to work in an open-world deployment model. Other agent authorization challenges, including agent identity, delegation governance, attestation, and attenuation, appear here only where they affect open-world trust bootstrapping rather than as the primary subject. # ๐Ÿงฑ The Closed-World Shape of OAuth OAuth's original deployment model ([RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749)) was mostly closed-world. Clients had fixed relationships with Authorization Servers (ASes) and Resource Servers (RSes). Developers built the client, read the API docs, registered the software statically, and learned ahead of time which scopes were required for which endpoints. Registration happened before runtime. Trust was established at deploy time, not discovered dynamically during execution. When the actor set is finite and known, the threat model is legible. The principals are enumerated. The trust relationships are explicit. The attack surface can be studied and hardened through deployment experience. That boundedness is a major reason the [OAuth Security Best Current Practices](https://datatracker.ietf.org/doc/html/rfc9700) could become so concrete over time: the assumptions were constrained enough to analyze rigorously and stable enough to harden through deployment. The attack surface of closed-world OAuth is still large. But it is *bounded*. An AS knows in advance which clients can approach it, which RSes it issues tokens for, and the expected shape of every authorization relationship. That makes it possible to constrain token audiences, detect anomalies, and eliminate whole categories of trust bootstrapping problems by construction. [Authorization server metadata](https://datatracker.ietf.org/doc/html/rfc8414) ([RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414)), first established in OpenID Connect Discovery and later generalized for OAuth, made clients more adaptive by letting them discover protocol endpoints and capabilities rather than hand-configuring every URL. [Resource Indicators](https://datatracker.ietf.org/doc/html/rfc8707) ([RFC 8707](https://datatracker.ietf.org/doc/html/rfc8707)) let a single AS issue tokens for multiple RSes with different audiences and scopes. These were real improvements to a model whose core assumptions stayed mostly intact: the AS still knew its RSes, the client still knew its AS, and the developer still configured the relationships before runtime. # ๐Ÿ”“ Why Earlier Attempts Did Not Close the Gap [Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591) ([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)) was the most direct attempt to open OAuth up. In theory, DCR let a client discover an AS, register itself, and begin interacting without a prior bilateral setup process. In practice, it was never enough for genuinely open-world deployments. The problem was trust bootstrapping. If a client can self-assert its identity and metadata to any AS it encounters, registration becomes easy to abuse. A malicious client presents itself as a well-known brand. There is nothing in the protocol preventing it. The AS has no reliable way to validate the client's claimed identity against anything authoritative. Software Statements were designed to fix this: a signed assertion from a trusted third party vouching for the client's identity. But that required a trust-anchor ecosystem that never materialized at scale. Who issues them? Under what policies? Why should an arbitrary AS trust the issuer? Those questions were never answered end-to-end for open internet use. DCR works well inside controlled ecosystems: enterprise deployments, managed federations, and developer platforms where a platform operator already has a bilateral relationship with the AS. But those are still bounded environments that happen to provision clients dynamically. The gap between that model and true first-contact trust was never closed. OAuth 2.1 takes a different step. It consolidates security guidance accumulated over fifteen years of deployment, removes outdated patterns like implicit flow and password grant, and gives deployers a cleaner baseline. But [OAuth 2.1](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/) is a modernization of the closed-world model. It makes the existing model more secure and more deployable. It does not redefine the model around runtime discovery and open-world trust. OAuth 2.1 does not give a client a runtime path for discovering how a protected resource is protected. It does not provide a mechanism for an AS to evaluate a client's identity in a web-native way before the client has ever been registered. It does not address how a client confirms which resource binding a token actually carries after issuance. If your deployment is fundamentally closed-world (fixed clients, pre-configured ASes, known RSes), OAuth 2.1 is the modernization you need. If your deployment is fundamentally open-world, OAuth 2.1 is a better floor, not the model you need to reach. # ๐Ÿค– Agents Invert the Deployment Assumption Agents do not operate in closed worlds. They discover tools, services, and protected resources at runtime. A simple example is a tool protocol like [Model Context Protocol (MCP)](https://modelcontextprotocol.io/): an agent loads a tool manifest from a URL it just discovered, calls an endpoint, receives a `401 Unauthorized`, and has no prior knowledge of which AS protects that resource, which resource identifier to request, or which scopes are required. The agent was not configured at deploy time with a list of every RS it will need. To be precise: "open world" here does not mean "enterprise dynamic onboarding" or "managed federation with known trust anchors." It means first-contact interaction with resources and authorization servers that were not pre-configured into the client at deployment time. The closed-world question is: how does a known client get a token from a known AS for a known RS? The open-world question is: how does a client safely discover a protected resource, learn how that resource is protected, determine which AS to use, determine the correct resource identifier and scopes, confirm that the discovered AS is actually the right one, and do all of this without prior configuration? Different deployment model. Different protocol primitives. Different threat surface. # ๐Ÿงญ The New Standards That Start to Open OAuth Up One recently published RFC and a closely related active draft together address the core discovery problem. **[Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728)** gives the client a runtime path from "I found a protected resource" to "I know how to get the right token for it." The resource advertises the AS it uses, the resource identifier, and other authorization requirements. A client that encounters a `401` with a `WWW-Authenticate` challenge can use that challenge to locate the resource's metadata document, learn which AS issues tokens for it, and proceed from there. **[OAuth Client ID Metadata Document](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/)** addresses a narrower but important complementary problem: how an AS can evaluate client metadata for a client instance it has never seen before without relying only on self-asserted registration input. Rather than accepting client metadata only in-band in a registration request (where DCR's trust problem originates), the client publishes a metadata document at a well-known URL under its own domain. The AS independently fetches and verifies it over TLS, anchoring client identity in DNS and HTTPS without importing the full browser security model. The client is no longer vouching for itself only in-band; the AS can verify metadata against a stable, independently fetchable identity anchor. This model is parallel to authorization server metadata and OpenID Connect Discovery: a party publishes metadata at a well-known HTTPS URL, and relying parties trust it because TLS anchors it to a specific DNS origin. CIMD extends that pattern to the client side. Adjacent workload-identity work matters here too. The ongoing [OAuth SPIFFE Client Authentication](https://datatracker.ietf.org/doc/draft-ietf-oauth-spiffe-client-auth/) draft, alongside the [AI Agent Authentication and Authorization](https://datatracker.ietf.org/doc/draft-klrc-aiagent-auth/) draft that treats agents explicitly as workloads, profiles how SPIFFE identities and workload attestation can be used for OAuth client authentication. That is not the same trust model as CIMD, and it does not by itself create a unified first-contact bootstrap story for open-world sub-agents. It is a complementary piece for deployments where the caller is better modeled as an attested workload inside a managed trust domain than as a traditional web-hosted software client. Work in this area also connects back to CIMD by defining metadata parameters such as `spiffe_id` and `spiffe_bundle_endpoint`, which help bridge origin-based client discovery and SPIFFE-backed client authentication without collapsing the two models into one. A third layer sits between software-client identity and workload identity: agent-instance identity. CIMD anchors who the software client is; SPIFFE anchors what process is running. Neither addresses the identity of a specific agent invocation, which is an ephemeral, task-scoped principal that may call multiple resources within a single execution context or spawn sub-agents that need a verifiable identity derived from the parent authorization. There is no current standard for how an agent instance asserts a durable, scoped identity across the lifetime of a task, or for how a sub-agent's identity is provably bound to its parent's authorization context in a way that downstream resources can verify. CIMD has a clear boundary. It prevents impersonation of established services: an attacker who does not control `example.com` cannot publish a fraudulent CIMD document for a client claiming to be hosted there. It does not prevent look-alike domains. That is the inherent limit of any DNS-anchored identity system. That still leaves a policy question for the AS: proving control of a domain is not the same thing as deciding that a client hosted at that domain should be trusted for a particular kind of interaction. CIMD improves identity anchoring. It does not replace local trust policy. It also leaves a deployment-shape question. CIMD is strongest for clients that can anchor themselves in DNS and HTTPS. Agents increasingly involve a mix of public clients, confidential clients, sub-agents, and short-lived workloads that may be better modeled as attested workloads than as traditional domain-hosted software. How those client classes authenticate, identify themselves, and compose in truly open-world deployments is still incomplete work rather than a settled standards path. > PRM answers most of: where should the client go, and what should it ask for? > > CIMD answers part of: who is this client, and what metadata is it asserting from a stable origin? Together, they move OAuth toward a model built on runtime discovery, HTTPS-anchored identity, and DNS-based origin verification rather than on the assumption that every trust relationship was arranged manually in advance. They still leave the policy question of whether a given AS should trust a newly encountered client for a given interaction. # ๐ŸŒ OAuth Is Reaching For Web-Scale Trust Primitives OAuth was always web-native. It runs on HTTP, uses browser redirects, and was built around URIs from the start. What is changing is that OAuth is now reaching for the layer of the web it never needed before: the trust model browsers developed for open-world, first-contact interactions with parties that have no prior relationship. The web developed patterns for this problem, including anchoring identity in DNS origins backed by TLS, treating unknown cross-origin parties as untrusted by default, and verifying content integrity independently of the delivery channel. Those patterns exist because the web had to work at internet scale without assuming prior bilateral configuration. OAuth did not need them because its deployment model was closed-world. PRM uses a related origin-anchoring pattern: resource identity is grounded in the same TLS origin as the resource itself. CIMD extends a similar idea to the client side, anchoring who a client is in DNS rather than in self-asserted registration input. Signed metadata would add independent content verification, validating a metadata document without relying only on the delivery channel that served it. That analogy is illustrative rather than complete. It holds for the discovery and metadata layer: origin anchoring, independently verifiable artifacts, and runtime trust evaluation rather than pre-configured bilateral relationships. It stops being useful once the problem shifts to delegation semantics, workload identity, authorization-server trust evaluation, or Mission shaping. Those are the gaps that begin once discovery succeeds, and they require protocol primitives the web never needed to develop. # ๐Ÿงช A Concrete Example of the Open-World Flow Imagine an agent helping a salesperson prepare an account-renewal brief. The agent discovers a CRM MCP tool at runtime. It calls a `get-account` operation and receives a `401` challenge. The `WWW-Authenticate` header in the response points to the resource's metadata document. PRM returns the AS URL, the effective `resource` identifier, and the required authorization parameters. The agent uses that information to request a token. That is the discovery layer working as intended. What the example also exposes is where the subsequent layers break. If the AS returns a token without echoing the effective `resource` binding, the agent cannot confirm whether the token is valid for the account API it just discovered. If the CRM AS is newly encountered, the client still has to decide whether it should trust that AS at all. If the workflow later points the agent toward a billing API in another trust domain, the delegation and issuer-acceptance problem repeats. That full arc, from discovery through resource binding through first-contact trust, is the substrate open-world OAuth has to make reliable. The next section addresses two specific gaps that break that substrate in practice; the deeper semantic and governance questions begin where the substrate ends. # โš ๏ธ Two Gaps That Break Discovery in Practice PRM and CIMD point toward the right shape. But there are two specific gaps that still prevent the discovery flow from working reliably in real deployments. Without addressing them, open-world OAuth will produce predictable failures for agents at runtime. ## ๐Ÿ” Resource Identifier Matching The first gap is in PRM itself. The standard requires the `resource` value returned through a `WWW-Authenticate`-driven metadata lookup to exactly match the URL the client requested. In practice, this breaks discovery for APIs that protect multiple paths under one authorization policy. A resource server protecting `/api/v1/calendar`, `/api/v1/email`, and `/api/v1/contacts` cannot serve a single metadata document with a single resource identifier; it would need one per path. Many real APIs are structured this way. [Update to OAuth 2.0 Protected Resource Metadata Resource Identifier Validation](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-rfc9728bis/) addresses this with a narrow, targeted change: the advertised resource identifier may be a path prefix of the requested URL rather than an exact match, while keeping the same TLS origin requirement that prevents cross-origin resource impersonation. The security boundary is preserved. The practical deployment constraint is removed. ## ๐Ÿ”— Resource Binding Confirmation The second gap is more serious. Even after a successful discovery flow, an agent that receives an access token has no standard way to confirm what that token is actually valid for. [Resource Indicators](https://datatracker.ietf.org/doc/html/rfc8707) ([RFC 8707](https://datatracker.ietf.org/doc/html/rfc8707)) let the client declare which resource it wants the token for, but there is no corresponding mechanism for the AS to confirm which resource binding it honored. An AS may silently ignore the requested `resource`, bind the token to a different identifier based on policy, or accept only a subset of what was requested. The client sends the token to the discovered resource and receives a `403`. The client cannot tell why, cannot detect this before sending, and has no interoperable way to recover. This is not an edge case. In any multi-resource or dynamically discovered environment, silent resource binding divergence is a realistic failure mode, not a theoretical one. [OAuth 2.0 Resource Parameter in Access Token Response](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-resource-token-resp/) closes the loop by having the AS echo back the effective `resource` in the token response. The client knows what resource binding was honored before it sends the token anywhere. | Gap | Where | Problem | Fix | |---|---|---|---| | Resource identifier matching | PRM | `resource` must exactly match the requested URL; breaks multi-path APIs | [rfc9728bis](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-rfc9728bis/): prefix-match instead of exact-match | | Resource binding confirmation | Token response | No standard way to verify which `resource` binding the AS honored | [resource-token-resp](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-resource-token-resp/): AS echoes effective `resource` in the token response | > Discovery finds the resource. The token request declares it. The token response confirms it. If you are implementing or deploying OAuth for agentic systems, these two drafts are where review and implementation feedback will have the most direct impact on whether the discovery model actually works. Those gaps are targeted and fixable. The gaps described in the next section run deeper. # ๐Ÿ•ณ๏ธ What Is Still Not Solved Solving the discovery layer is necessary but not sufficient. Even when PRM, CIMD, and the two gap-closing drafts are all in place, a generic agent still faces unsolved problems at the trust-framework and governance layers. | Layer | Main question | Examples | |---|---|---| | Protocol | Can the client discover protection requirements and get the right token? | PRM, RFC 8707, `resource` confirmation, DPoP, PAR | | Trust framework | Why should either side accept the other on first contact? | Issuer policy, federation, signed metadata, workload attestation | | Governance / Mission layer | Is the newly discovered authority still inside the approved task? | Covered in [Part 2](/notes/open-world-oauth-still-needs-mission-shaping/) | For open-world OAuth to be usable end-to-end, all three layers need to work. PRM and the two drafts above make real progress on the protocol layer. Adjacent agent and workload-identity work sharpens the identity side of the problem: open-world trust now has to compose not just with software clients in the abstract, but with attested workloads, ephemeral sub-agents, and multi-hop execution chains. What remains in this post falls into three categories: a security-baseline adoption gap, metadata integrity, and first-contact trust. The semantic and governance gaps run deeper; they are the subject of [Part 2](/notes/open-world-oauth-still-needs-mission-shaping/). ## ๐Ÿ” Sender-Constrained Tokens Need to Be the Default Posture The technical answer to sender-constrained tokens already exists. [DPoP](https://datatracker.ietf.org/doc/html/rfc9449) (Demonstrating Proof-of-Possession at the Application Layer) sender-constrains access tokens to a specific key pair: a stolen token is useless without the corresponding private key. PRM defines `dpop_bound_access_tokens_required`, which lets a resource server signal that it requires DPoP-bound tokens. The mechanism is specified and implementable today. The gap is not the mechanism. It is adoption and mandate. In a closed world, bearer tokens are risky but manageable: the token audience is known, the RS validates against its configured AS, and the blast radius of a stolen token is bounded by pre-existing trust relationships. In an open world, tokens acquired from dynamically discovered authorization servers carry amplified replay risk. No baseline open-world OAuth mandate requires an AS to support DPoP, and nothing in the current standards makes sender-constrained tokens the expected posture for open-world deployments rather than an opt-in capability. The closest existing baseline is [FAPI 2.0 Security Profile](https://openid.net/specs/fapi-security-profile-2_0.html), which mandates DPoP or mutual TLS for regulated financial API deployments and demonstrates that such a mandate is implementable at industry scale. FAPI applies to a specific regulated domain, not to open-world OAuth broadly. But it is the clearest existing evidence that a sender-constraint mandate can be specified, deployed, and hardened. What is missing is an equivalent baseline for open-world agentic contexts. [Pushed Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9126) ([PAR](https://datatracker.ietf.org/doc/html/rfc9126)) address a related concern for interactive, user-present authorization flows. In open-world deployments where clients are not pre-registered and redirect URIs cannot be tightly validated in advance, authorization request injection becomes more realistic. PAR mitigates this by having the client push the full authorization request to the AS before the browser redirect. [PKCE](https://datatracker.ietf.org/doc/html/rfc7636) ([RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636)) is the complementary baseline defense for authorization code interception in public-client flows. For agent-to-agent and machine-to-machine flows, which dominate agentic systems, DPoP is the more directly applicable sender-constraint mechanism; PAR and PKCE apply where a user-present redirect flow is involved. Mutual TLS sender-constrained tokens ([RFC 8705](https://datatracker.ietf.org/doc/html/rfc8705)) are another established option. But for open-world and web-native clients, DPoP is the more natural fit because it does not assume pre-existing certificate provisioning. ## ๐ŸŽฏ Metadata Integrity Under Adversarial Conditions The open-world discovery model depends on resource servers serving accurate metadata. A malicious resource server can serve metadata pointing to an attacker-controlled AS. A client that completes an authorization flow against that AS can end up delivering an authorization code to the wrong security domain, potentially for an account at a legitimate service. This is structurally analogous to open redirect vulnerabilities: the discovery mechanism becomes a vector for directing clients toward attacker-controlled infrastructure. The current protections, HTTPS delivery and the same-origin requirement for `resource` values in PRM, assume the resource server is honest. Signing metadata documents with JWS, using a key whose binding is verifiable independently of the TLS delivery channel, would let a client verify that a metadata document was signed by a key it has reason to trust. The cryptographic primitives already exist in JSON Object Signing and Encryption (JOSE). What does not exist is a standard for how resource servers publish signing keys, how clients discover and evaluate them, and what trust policy applies on first encounter. [OpenID Federation 1.0](https://openid.net/specs/openid-federation-1_0.html) is the closest existing answer: its entity statements are JWS-signed metadata documents, and its trust chains let parties establish trust without prior bilateral configuration by tracing signed assertions to a common trust anchor. Active deployment in eIDAS 2.0 gives it more than theoretical standing. The constraint is that both parties must be enrolled in a shared federation, which moves the closed-world assumption up one level rather than eliminating it. For first contact between parties with no common trust anchor, the metadata integrity problem remains open. This is distinct from the authorization server trust problem below. Here the question is whether the metadata document itself is authentic. The next question is whether the AS that document points to is one the client should trust at all. ## ๐Ÿค First-Contact Trust Is Bilateral The first-contact trust problem applies in both directions. A client that receives an AS URL from newly discovered resource metadata needs a way to evaluate whether that AS should be trusted at all. A resource server that receives a token from an unknown issuer faces the same problem in reverse. The current standards leave both sides underspecified. On the client side, PRM tells a client which AS to use. It does not tell the client whether to trust that AS. In a closed world this question does not arise: the AS was configured at deploy time. In an open world, the AS URL comes from metadata discovered at runtime. If that metadata was served by a compromised or malicious resource server, the AS URL could point anywhere. The current protections rely on HTTPS and the Web Public Key Infrastructure (WebPKI): the AS must use valid TLS, and the resource metadata must be served from the same TLS origin as the resource. This does not address a resource server that is malicious rather than compromised, or one whose metadata can be influenced without full TLS compromise. [Authorization Server Issuer Identification (RFC 9207)](https://datatracker.ietf.org/doc/html/rfc9207) helps bind an authorization response to the issuing AS, but it does not answer whether that AS should have been trusted in the first place. On the resource server side, JWT-structured access tokens ([RFC 9068](https://datatracker.ietf.org/doc/html/rfc9068)) provide a partial answer. The token is self-contained, carries standard claims including `iss` and `aud`, and can be validated by fetching the issuer's JWK Set via authorization server metadata discovery ([RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414)). A dynamically discovered RS can validate any token whose issuer publishes standard AS metadata, without needing to pre-register with that AS. But a valid JWT signature from an unknown issuer tells the RS only that it has a cryptographically well-formed token from *some* AS. It does not tell the RS whether that AS is one this resource should accept tokens from at all. Token introspection ([RFC 7662](https://datatracker.ietf.org/doc/html/rfc7662)) does not solve that first-contact problem: it requires the RS to already know where to send the token for validation, which presupposes the pre-existing AS relationship it does not have. What is missing for both sides is a deeper trust channel independent of TLS delivery. Signing AS metadata with a JSON Web Signature ([JWS](https://datatracker.ietf.org/doc/html/rfc7515)) key whose binding can be verified out-of-band would give a client a way to evaluate a metadata document regardless of whether the delivery path was intact, and would give an RS a way to evaluate issuer trustworthiness beyond signature mechanics. What does not exist is a standard for how AS signing keys are published via [JSON Web Key (JWK) Sets](https://datatracker.ietf.org/doc/html/rfc7517) ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)), how either party discovers them on first contact, and what trust policy applies. At minimum, an RS needs some policy basis for acceptance: issuer allowlists, federation membership, signed metadata anchored in a trust framework, or some equivalent rule that answers not just "is this token valid?" but "is this issuer one I should accept tokens from at all?" That remains open work on both sides of the trust relationship. The web's experience with PKI and ACME is instructive. Web PKI solved open-world first-contact trust at internet scale by reducing identity to a verifiable property (domain control), delegating trust through a hierarchy of signed assertions, and making certificate issuance auditable through Certificate Transparency. ACME then demonstrated that automating trust bootstrapping, rather than requiring manual bilateral coordination for every new relationship, is what drove TLS adoption from a minority to a near-universal baseline. OAuth already relies on Web PKI for transport security. The open gap is the application layer above TLS: a standard for verifiable AS identity, an automated bootstrapping mechanism for AS trust, and a transparency mechanism for issuer metadata. The problem is not unsolvable. The architecture exists. The OAuth-specific instantiation does not yet. # ๐Ÿšช Closed World Was a Feature. Open-World OAuth Is the Next Step. OAuth became robust because it was designed around constrained assumptions and hardened over years of deployment and analysis. Agents expose a different assumption set. They operate in open worlds, encounter resources dynamically, and need a trust model that works without prior bilateral registration for every relationship they may encounter. The newer OAuth work, including PRM, CIMD, and the gap-closing drafts, represents the first serious structural movement toward native open-world OAuth. These are not incremental additions to the old model. They are changes to its foundational deployment assumptions. The closed-world model gave OAuth the stability to become mature. The open-world extensions now in progress are the work required to make that maturity applicable to the next generation of clients operating in environments OAuth was never designed for. That also means a large surface area has to evolve for OAuth to become truly capable in open-world agent ecosystems. There is real value in evolving the infrastructure we already have. OAuth, OpenID Connect, and the surrounding deployment base are too important to bypass. But this path will take time because it touches discovery, trust bootstrapping, sender constraints, and metadata integrity across several specifications rather than one. The remaining gaps are easier to state than to solve. Some are protocol-standardization problems; others require coordination across trust frameworks and multiple specifications. Adjacent work such as [AAuth](https://dickhardt.github.io/AAuth/draft-hardt-aauth-protocol.html) (editor's copy, accessed April 7, 2026) takes a different angle by redesigning authorization choreography around open-world assumptions from the start. That deserves attention, but the narrower point for this post is the OAuth substrate: discovery, resource binding, sender constraints, metadata integrity, and first-contact trust all have to work before higher-level agent authorization can be reliable. Two of those gaps are targeted and fixable now: the resource identifier matching fix and the resource binding confirmation draft described earlier in this post. The rest require deeper ecosystem work. Without a substrate that can handle runtime discovery, resource binding, and first-contact trust, the rest of the authorization stack is built on the wrong assumptions. That is where [Part 2](/notes/open-world-oauth-still-needs-mission-shaping/) picks up: once discovery and first-contact trust exist, how does approved intent become bounded authority across delegation, tool semantics, consent continuity, and the full lifecycle of a task? --- # Standardize `act` Across Assertion Grants and JWT Access Tokens Canonical URL: https://notes.karlmcguinness.com/notes/standardize-act-across-assertion-grants-and-jwt-access-tokens/ Markdown URL: https://notes.karlmcguinness.com/notes/standardize-act-across-assertion-grants-and-jwt-access-tokens.md > **Update (2026-04-30):** This proposal has been published as an IETF individual draft, [OAuth Actor Profile (`draft-mcguinness-oauth-actor-profile`)](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-actor-profile/), which turns the recommendations below into a concrete specification. OAuth has a delegation visibility problem. In many deployments, a token tells you that *someone* is acting, but not clearly who is acting for whom. Delegation is implied by context, encoded in `sub` by convention, or inferred from `client_id` heuristics. That might be acceptable inside a single product boundary. It is not acceptable for standards-based interoperability. > The fix is not a new claim. The primitives already exist. What is missing is a shared profile that applies them consistently. The OAuth WG should standardize one actor model across both: - JWT assertion grants ([RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523) and profiles built on top of it, including [Identity Assertion JWT Authorization Grant (ID-JAG)](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/)) - JWT access tokens ([RFC 9068](https://datatracker.ietf.org/doc/html/rfc9068)) Standardizing `act` using [OAuth Entity Profiles (Entity Profiles)](https://datatracker.ietf.org/doc/html/draft-mora-oauth-entity-profiles-00) would make delegation and principal type explicit and machine-processable at both surfaces. # ๐Ÿ” Where the Current Specs Leave a Gap ## `act` Exists, But Is Not Profiled Where It Matters [OAuth 2.0 Token Exchange (Token Exchange)](https://datatracker.ietf.org/doc/html/rfc8693) defines `act` for token exchange. That is a good start. But the ecosystem treats actor semantics as optional and context-specific. Two standards-compliant implementations can still disagree about delegation meaning when a token crosses a domain boundary. The gap runs deeper at the assertion boundary. JWT assertion grant processing ([RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523) and related profiles, such as [ID-JAG](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/)) does not require a typed, interoperable actor model. So delegation introduced at the federation boundary does not survive into token exchange or downstream access tokens in any consistent way. ## JWT Access Tokens Overload `sub` In most [RFC 9068](https://datatracker.ietf.org/doc/html/rfc9068) deployments today, `sub` is doing too much: - Is `sub` the end-user who authorized access? - Is `sub` the workload client acting autonomously? - Is `sub` an AI agent acting on someone's behalf? This is not just an OAuth plumbing question. As explored in [You Don't Give Agents Credentials. You Grant Them Power of Attorney.](https://notes.karlmcguinness.com/series/you-dont-give-agents-credentials-you-grant-them-power-of-attorney/), the identity and delegation semantics carried in tokens are the foundation on which any meaningful authority governance for agents has to be built. You cannot govern what you cannot see. When a resource server cannot answer that question from the token alone, it cannot reliably distinguish: - direct subject access, - user-delegated client access, or - non-user workload or agent access. Some implementations fall back on `client_id == sub` to infer "client acting as itself." That heuristic can work in simple single-hop cases, but it does not survive delegation chains and it says nothing about what kind of principal either party is. That ambiguity creates policy drift. Authorization decisions diverge, audit trails lose fidelity, and security reviews turn into arguments over interpretation. ## Actor Identity Is Asserted, Not Bound Even after `act` is populated, the actor claim is just a string. There is no cryptographic guarantee that the entity presenting the token is the same entity identified in `act.sub`. A stolen token can be replayed by a different actor, and the resource server has no way to tell. [Proof-of-Possession Key Semantics for JWTs (RFC 7800)](https://datatracker.ietf.org/doc/html/rfc7800) defines `cnf` to bind a token to a holder's key. The `jkt` member carries a SHA-256 JWK Thumbprint of the holder's public key. [DPoP-Protected JWT-Secured Authorization Grants (PoP JAG)](https://datatracker.ietf.org/doc/html/draft-parecki-oauth-jwt-dpop-grant-01) and [Identity Assertion JWT Authorization Grant (ID-JAG), Section 8.4](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-identity-assertion-authz-grant-02#section-8.4) both support sender-constraining the current presenter: the assertion includes `cnf.jkt`, the client presents a DPoP proof, and the authorization server validates that the proof's public key matches the asserted thumbprint. No matching proof, no token. Key binding is not required for every delegation scenario. Many internal workload deployments are fine with bearer semantics. But when an actor presents a DPoP key binding at the token endpoint, the issued token should carry that actor's key at the top-level `cnf`. On the next exchange hop, the newly issued token should repeat that pattern for the next presenter while preserving prior actor keys in the `act` chain as delegation history. If a `cnf.jkt` established at the assertion grant boundary is silently dropped in the issued access token, the resource server cannot enforce a sender constraint the authorization server already accepted. > Identity semantics and delegation semantics must be explicit protocol data, not institutional memory. Key binding makes actor identity verifiable, not just visible. # ๐Ÿ”ง The Proposal: `act` + Entity Profiles The approach combines existing pieces: - **`act`** as the explicit delegation vehicle (per Token Exchange). - **Entity profile claims** (`sub_profile`, `client_profile`) to make principal type explicit on each principal, including within nested `act` nodes. - **Top-level `cnf` with `jkt`** for the current token presenter when that presenter established a DPoP key binding, consistent with [PoP JAG](https://datatracker.ietf.org/doc/html/draft-parecki-oauth-jwt-dpop-grant-01), [ID-JAG Section 8.4](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-identity-assertion-authz-grant-02#section-8.4), and [RFC 7800](https://datatracker.ietf.org/doc/html/rfc7800). Prior actor keys may be preserved inside nested `act` nodes as delegation history, but only the top-level `cnf` is the live sender constraint the resource server enforces. - **The same model applied to both surfaces**: JWT assertion grants and JWT access tokens. The natural vocabulary for profile semantics is [Entity Profiles](https://datatracker.ietf.org/doc/html/draft-mora-oauth-entity-profiles), which defines `sub_profile` and `client_profile`. The actor-chain profile should align with that vocabulary rather than creating a parallel taxonomy. In the current draft, standardized values include `user`, `device`, `native_app`, `web_app`, `browser_app`, `service`, and `ai_agent`, and profile claims are space-delimited strings when multiple values are present. For interoperable processing across trust domains, each principal and delegation relationship must be explicit. The resulting contract is: | Claim | Meaning | |---|---| | `iss` | Issuer asserting the principal and delegation relationship | | `sub` | Principal whose authority is being exercised | | `act` | Principal currently acting on behalf of `sub` (when delegation exists) | | `sub_profile` | Principal profile value(s) for `sub` or for any `act` node | | `cnf.jkt` | SHA-256 JWK Thumbprint of the current presenter's key; carried at the top level when the current actor established a DPoP binding | | `act.cnf.jkt` | Optional preserved thumbprint for a prior actor in the delegation chain; useful for audit and provenance, not live sender-constrained enforcement | No new grant type. No new token type. A shared profile and processing rules built on what already exists. # ๐Ÿ’ก What This Looks Like in Practice ## JWT Access Token: Before ```json { "iss": "https://as.example.com", "aud": "https://api.example.com", "client_id": "client-123", "sub": "248289761001", "scope": "payments:write", "exp": 1773076800 } ``` A resource server cannot determine whether `sub` is a user, a client instance, or an agent identifier. It cannot tell whether this is direct access or delegated access. That ambiguity is exactly what a standard should eliminate. ## JWT Access Token: After ```json { "iss": "https://as.example.com", "aud": "https://api.example.com", "client_id": "client-123", "sub": "248289761001", "sub_profile": "user", "cnf": { "jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I" }, "act": { "sub": "agent-7f3c", "iss": "https://as.example.com", "sub_profile": "ai_agent" }, "scope": "payments:write", "exp": 1773076800 } ``` Now the resource server can evaluate both principals explicitly. Here the current actor established a DPoP key binding during token exchange, so `cnf.jkt` is present at the top level and the agent must present a matching DPoP proof. If no key binding was established, top-level `cnf` is absent and bearer semantics apply. No heuristics. No local conventions. # ๐ŸŒ The Canonical Cross-Domain Case The most important scenario to get right is cross-domain delegation, where a federation boundary is crossed and then token exchange carries the principal chain downstream. `planner-agent` is an external AI agent from `assistant.example` acting on behalf of Alice. It uses `hotel-tool` at `tools.example`, which must in turn call an internal backend at `inventory.example`, a service the agent cannot reach directly. The flow covers four steps. Alice signs in and the agent receives a DPoP-bound refresh token. The agent exchanges that for a cross-domain ID-JAG. The agent presents the ID-JAG to obtain a tool access token, still bound to the agent's key. Finally, `hotel-tool` performs its own Token Exchange to reach the backend, shifting the live sender constraint to the tool's key. That last step is the point: the originating agent and the current presenter are not the same actor on every hop. | Role | Entity Type | Subject ID | OAuth Client | Key Binding (`jkt`) | |---|---|---|---|---| | User | `user` | `user-alice` | No | n/a | | AI agent | `ai_agent` | `planner-agent` | Yes | `NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs` | | Tool | `service` | `hotel-tool` | Yes | `R3g0XuBFHRTqAq3HyOVSLWLBXb-RypXz6NsKrOSqMmE` | ## Step 1: Authorization Request Alice is using `planner-agent` and signs in with `assistant.example`. The agent sends her through a standard OIDC authorization flow, using authorization code binding via `dpop_jkt` so the resulting code is tied to the agent's key. The authorization request looks roughly like this: ```text GET /authorize? response_type=code &client_id=planner-agent &redirect_uri=https%3A%2F%2Fagent.assistant.example%2Fcallback &scope=openid profile offline_access hotels:search hotels:book &state=af0ifjsldkj &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM &code_challenge_method=S256 &dpop_jkt=NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs ``` After Alice authenticates, the agent redeems the code at the token endpoint and proves possession of the same key with DPoP: ```text POST /token Content-Type: application/x-www-form-urlencoded DPoP: grant_type=authorization_code &code=SplxlOBeZQQYbYS6WxSbIA &redirect_uri=https%3A%2F%2Fagent.assistant.example%2Fcallback &client_id=planner-agent &code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk ``` The response below is abbreviated but still shows the surrounding token fields for realism. The artifact that matters for the next step is the DPoP-bound refresh token, which the agent will later use to mint an ID-JAG for cross-domain access. ```json { "access_token": "...", "id_token": "", "refresh_token": "", "token_type": "DPoP" } ``` At this point the agent has a user-authenticated session and a refresh token bound to its key, but the cross-domain delegation semantics are not yet packaged into a JWT grant another authorization server can consume directly. ## Step 2: Refresh Token to ID-JAG `planner-agent` uses that refresh token as the `subject_token` in Token Exchange to obtain an ID-JAG for `hotel-tool` in another trust domain. The request might look like this: ```text POST /token Content-Type: application/x-www-form-urlencoded DPoP: grant_type=urn:ietf:params:oauth:grant-type:token-exchange &subject_token= &subject_token_type=urn:ietf:params:oauth:token-type:refresh_token &requested_token_type=urn:ietf:params:oauth:token-type:id-jag &audience=https%3A%2F%2Fauth.tools.example%2Ftoken &scope=hotels:search hotels:book ``` That exchange does not change the delegation model. It packages the delegated user and acting agent into an ID-JAG that another authorization server can validate directly. The token exchange response might look like this: ```json { "issued_token_type": "urn:ietf:params:oauth:token-type:id-jag", "token_type": "N_A", "access_token": "" } ``` Even though the issued artifact is an ID-JAG rather than an access token, Token Exchange still returns it in the `access_token` response field and relies on `issued_token_type` to tell the client what it actually received. The resulting ID-JAG might look like this: ```json { "iss": "https://idp.assistant.example", "sub": "user-alice", "sub_profile": "user", "cnf": { "jkt": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs" }, "act": { "iss": "https://idp.assistant.example", "sub": "planner-agent", "sub_profile": "ai_agent" }, "scope": "hotels:search hotels:book", "aud": "https://auth.tools.example/token", "exp": 1773076800 } ``` The delegation is explicit in the ID-JAG itself: Alice authorized `planner-agent` to act for her. `planner-agent` established a DPoP key binding when the grant was issued, so `cnf.jkt` appears at the top level. That binding remains part of the chain until a later token exchange mints a new access token for a different current presenter. ## Step 3: ID-JAG to Tool Access Token `planner-agent`, not `hotel-tool`, presents the ID-JAG to `auth.tools.example`. Because the grant is DPoP-bound, the agent uses the JWT-DPoP grant and proves possession of the same key that is referenced in the ID-JAG's top-level `cnf.jkt`. The request might look like this: ```text POST /token Content-Type: application/x-www-form-urlencoded DPoP: grant_type=urn:ietf:params:oauth:grant-type:jwt-dpop &assertion= &scope=hotels:search hotels:book ``` The tools authorization server validates federation trust, validates the ID-JAG and the agent's proof of possession, and issues an access token for `hotel-tool` still bound to `planner-agent`'s key. That tool access token might look like this: ```json { "iss": "https://auth.tools.example", "aud": "https://api.tools.example/hotel-tool", "sub": "user-alice", "sub_profile": "user", "scope": "hotels:search hotels:book", "cnf": { "jkt": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs" }, "act": { "iss": "https://auth.tools.example", "sub": "planner-agent", "sub_profile": "ai_agent" }, "exp": 1773078600 } ``` The current actor is still `planner-agent`, because it is the entity presenting this access token to `hotel-tool`. The live sender constraint remains the agent's top-level `cnf.jkt`. At this point there has been no key transition yet. ## Step 4: Tool Token Exchange for Backend Service `hotel-tool` receives the inbound access token when `planner-agent` calls it. To reach `inventory.example`, it performs one more Token Exchange using that token as the `subject_token` and presenting its own DPoP proof. This is where the live sender constraint shifts from the agent's key to the tool's key. The request might look like this: ```text POST /token Content-Type: application/x-www-form-urlencoded DPoP: grant_type=urn:ietf:params:oauth:grant-type:token-exchange &subject_token= &subject_token_type=urn:ietf:params:oauth:token-type:access_token &audience=https%3A%2F%2Finventory.example &scope=inventory:reserve ``` The backend authorization server validates the inbound tool token, preserves the actor chain, validates `hotel-tool`'s proof of possession for the new audience, and issues a backend access token bound to the tool's key. The resulting backend access token might look like this: ```json { "iss": "https://auth.inventory.example", "aud": "https://api.inventory.example/reservations", "sub": "user-alice", "sub_profile": "user", "scope": "inventory:reserve", "cnf": { "jkt": "R3g0XuBFHRTqAq3HyOVSLWLBXb-RypXz6NsKrOSqMmE" }, "act": { "iss": "https://auth.inventory.example", "sub": "hotel-tool", "sub_profile": "service", "act": { "iss": "https://auth.tools.example", "sub": "planner-agent", "sub_profile": "ai_agent", "cnf": { "jkt": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs" } } }, "exp": 1773078600 } ``` The current presenter is now `hotel-tool`, so the live sender constraint is the tool's top-level `cnf.jkt`. The nested `act` chain preserves `planner-agent` and the upstream key that established the original delegation. This is the key transition the profile needs to make explicit: each new access token binds only the current presenter, while the chain preserves who previously acted for whom. What this scenario demonstrates is why both surfaces must align. The ID-JAG and the downstream access tokens encode the same delegation, in the same model. The first cross-domain hop keeps `planner-agent` as the current presenter. The later backend hop changes the current presenter to `hotel-tool` and mints a new top-level sender constraint without losing the upstream actor chain. The AS does not need to translate between different actor representations as it crosses issuance boundaries. The resource server receives a token where principal types and delegation history are unambiguous across the full chain. > If assertion grants and access tokens use different delegation conventions, the ambiguity just moves one layer up. The alignment is the point. # โš™๏ธ Resource Server Processing With a standardized model, the resource server can implement stable, issuer-agnostic logic: ```text input: access_token jwt dpop_proof jwt // required when token.cnf.jkt is present 1) Validate token (sig, iss, aud, exp) per JWT AT profile (RFC 9068). 2) Resolve subject := token.sub Resolve subject_profiles := parse_profiles(token.sub_profile) 3) If token.cnf.jkt present: // live sender constraint for current presenter Compute thumbprint(dpop_proof.header.jwk) Verify computed thumbprint == token.cnf.jkt Verify dpop_proof signature valid for the key in dpop_proof.header.jwk Reject if mismatch 4) If token.act present: actor := token.act.sub // current actor (RFC 8693) actor_profiles := parse_profiles(token.act.sub_profile) evaluate policy.allow_delegate(actor_profiles, subject_profiles) evaluate policy.allow_actor_for_subject(actor, subject) evaluate policy.allow_scope_for_pair(token.scope, actor, subject) 5) If token.act absent: evaluate policy.allow_subject_self(token.scope, subject, subject_profiles) 6) Optionally log nested token.act.act... as delegation history for audit. Nested cnf.jkt values record the key binding of each prior actor in the chain. 7) Enforce decision. ``` The three-case decision tree for relying parties becomes: 1. `act` present: dual-principal policy evaluation (`sub` authority + `act` authority to act). 2. No `act`, `sub_profile` contains `user`: direct user-context access. 3. No `act`, non-user subject profile: non-delegated workload or agent self-access. `client_id` may still be an input, but it is not the delegation model. It cannot represent chained delegation and does not type either principal. This is the operational value of the profile: the resource server does not branch on issuer-specific convention to understand delegation semantics. Authorization, audit, and policy enforcement work the same way across implementations. # ๐Ÿ›ก๏ธ Deployment and Backward Compatibility This does not require a flag day. Existing deployments that only understand subject-only tokens continue to work. Explicit `act` is additive, and consumers that do not understand it can ignore it (with appropriate policy defaults). Discovery or profile metadata can signal capability for implementations that want to negotiate. The goal is not disruption. The goal is ending private delegation semantics for new and federated deployments where interoperability actually matters. # ๐Ÿ”Ž Caveat: Delegation Chain Is Not Execution Identity A nested `act` chain tells you who claims to act for whom. It does not prove that the current request is a valid continuation of the originating execution. The same delegation chain can appear in multiple unrelated executions. If each presenter holds the bound key for its hop, each presentation can still be valid under proof of possession. Sender-constraining answers "who is allowed to present this token," not "which execution produced this request." From a JWT, you can answer "who signed this" and, with `act` plus `cnf`, "who is acting for whom" and "who proved possession of the current key." You cannot answer "which execution is this" unless some separate execution identifier or continuity mechanism is standardized and propagated alongside the delegation chain. This proposal does not address execution identity or execution continuity. Its scope is limited to making delegation semantics and current presenter key binding explicit and interoperable across assertion grants and JWT access tokens. # ๐Ÿ“‹ Recommendation The OAuth WG should standardize an interoperable actor profile that: - reuses `act` from Token Exchange, - uses Entity Profiles vocabulary for principal typing (`sub_profile`) on each principal in the chain, - uses top-level `cnf.jkt` for the current presenter when a token is sender-constrained, while allowing prior actor keys to be preserved inside nested `act` nodes as delegation history, - applies uniformly to JWT assertion grants and JWT access tokens, - defines deterministic processing rules for AS validation and resource server authorization, including DPoP proof verification against top-level `cnf.jkt` when present. The primitive work is already done. `act` exists. Entity Profiles are being defined. Token Exchange is standardized. DPoP key binding for the current presenter is already specified in JWT grant work and in [ID-JAG Section 8.4](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-identity-assertion-authz-grant-02#section-8.4). What is needed is the profile that stitches them together across both token surfaces, makes the processing rules explicit, and ends the cross-profile ambiguity that has so far been left to implementer judgment. > Until that profile exists, delegation will remain a private convention masquerading as a standard. Two implementations can be fully RFC-compliant and still disagree about who is acting for whom. That is not an acceptable baseline for cross-domain identity, and it is the token-layer prerequisite for anything more ambitious. Governing delegated agent authority, enforcing mandate lifecycles, propagating revocation signals: none of it is tractable if the delegation relationship is invisible in the token. When "who is acting for whom" is portable protocol meaning rather than local folklore, the ecosystem gets better federation, better authorization policy, and better audit trails. That is worth standardizing. # Changelog - `2026-04-30`: This proposal has been published as an IETF individual draft, [OAuth Actor Profile (`draft-mcguinness-oauth-actor-profile`)](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-actor-profile/), which turns the recommendations here into a concrete specification. - `2026-03-18`: Clarified sender-constrained semantics so the current presenter uses top-level `cnf.jkt` and prior actor keys are preserved only as historical delegation context inside nested `act` nodes. - `2026-03-18`: Added explicit alignment to ID-JAG Section 8.4 for sender-constraining the current presenter while keeping nested prior-actor keys as profile-specific history. - `2026-03-18`: Reworked the canonical cross-domain example around an AI agent, a cross-domain tool, and a backend service, with an end-to-end flow from OIDC sign-in to ID-JAG issuance to downstream token exchanges, plus a cast table covering role, entity type, subject ID, OAuth client status, and key binding. - `2026-03-18`: Added an explicit caveat that this proposal does not address execution identity or execution continuity. --- # Mission Shaping Is Not Enough Canonical URL: https://notes.karlmcguinness.com/notes/mission-shaping-is-not-enough/ Markdown URL: https://notes.karlmcguinness.com/notes/mission-shaping-is-not-enough.md [Part 1](/notes/the-mission-shaping-problem/) argued that approved intent does not become governable authority on its own. In structured domains, Mission shaping can produce a bounded Mission Authority Model and a reviewable approval object. That is real progress. [The Mission Model](/notes/the-mission-model/) defines the Mission as a new authorization primitive โ€” the object that fills the gap between approved intent and governable authority โ€” and is the canonical reference for what a Mission is and what properties it carries. It is still not enough. The CFO example in Part 1 was the strong case: one enterprise, known systems, legible stages, and a control plane that can absorb transition friction. Even there, the hidden complexity was already visible. The agent still runs in the world. It still encounters external content, discovers new facts, spawns child agents, accumulates partial state, and continues after the moment of initial approval. That is where the second problem begins. Mission shaping defines the authority envelope (the [Mission](/notes/the-mission-model/) is the protocol object that carries it). Containment and runtime governance determine whether the system stays survivable when that envelope turns out to be incomplete. The Mission Model post makes the two-layer architecture explicit: the Mission is the envelope; the runtime layer is what keeps the system survivable when the envelope is wrong. # Where Mission Shaping Breaks Under Pressure The problems in this section all arise within a principled staged model, not only in undisciplined deployments. They are the pressure points where a coherent authority model begins to fray under operational reality. ## Scope Creep The staging model handles the case where an agent surfaces a discovered gap and requests governed expansion. [Part 1's](/notes/the-mission-shaping-problem/) context integrity section handles adversarial redirection. There is a third failure mode between them: quiet authority expansion. An agent decides that accomplishing the approved task requires something not originally anticipated, concludes it is obviously necessary, and does it without surfacing the discovery. No adversarial input. No explicit re-planning request. The agent's own judgment becomes the expansion mechanism. Preventing this requires a minimum-authority principle. The shaped envelope has to be narrow enough that "obviously necessary" actions outside the original approval are not silently inside the authority region. But minimum authority has its own failure mode: shape the envelope too narrowly and the system creates constant replanning churn. Operators get paged for predictable expansions. Teams respond by broadening every template until the model is no longer meaningfully bounded. This is not only a theoretical tradeoff. Empirical work on [semantic task-to-scope matching](https://arxiv.org/abs/2510.26702) shows the same tension: over-scoping grants too much authority, but under-scoping can stall task completion when the matcher fails to include necessary permissions. [IBAC's AgentDojo evaluation](https://ibac.dev/ibac-paper.pdf) makes the failure mode concrete: the permissive-mode breaches traced directly to over-scoped wildcard permissions that happened to cover the injected goal. The agent's reasoning was fully compromised. The authorization surface let the compromised action through. Strict mode blocked all 240 injection attempts by scoping permissions to specific recipients and resources, at the cost of requiring escalation for predictable prerequisites. That is why templates are necessary but not sufficient. Task templates are pre-approved Mission archetypes for known task classes. In the structured case, they may also be pre-compiled authority archetypes. A human has already approved that "board packet preparation for a CFO" maps to approximately this set of resources and operations. The template becomes the shaping baseline. Individual Missions attenuate from it rather than starting from scratch. This anchors minimum authority in prior human approval rather than in each operator's judgment call. Alongside templates, pre-approved expansion paths address predictable edge cases: known situations where discovery commonly reveals a need for one additional resource class, pre-authorized for this task type without requiring full re-authorization. Together, these two mechanisms reduce the re-planning friction that makes quiet expansion attractive. But templates accumulate exceptions. Left ungoverned, they grow until the template itself becomes a broad standing grant with a respectable name. This is the IE Trusted Sites failure described in [Part 1](/notes/the-mission-shaping-problem/): every enterprise application that did not work in the restricted zone got added to Trusted Sites because that was easier than fixing the application or tightening the template. The same pressure operates here. Every agent task that stalls on a missing permission gets the template broadened rather than the governed expansion path used. Eventually the template covers everything the agent might plausibly need and nothing is actually constrained. So templates have to be governed: versioned, reviewed, and retired when they become broader than the task class they were originally meant to represent. That governance is not optional. It is the mechanism that keeps minimum authority meaningful over time. ## Delegation When a Mission is delegated, the child Mission's authority model must be derived from the parent. It cannot exceed the parent envelope. [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) (OAuth Token Exchange) provides the protocol plumbing for this derivation, but the semantic constraint, that the child authority is a proper subset of the parent, is a Mission property โ€” formalized in [The Mission Model's Delegation component](/notes/the-mission-model/#what-a-mission-is) as one of the seven things a Mission carries. Enforcement of semantic attenuation is implementation-dependent and not a protocol guarantee. This is not a hypothetical risk introduced by agents. In production OAuth token exchange deployments today, child tokens routinely inherit full parent scope unless the implementation explicitly attenuates them. The multi-agent case compounds a failure mode already present in standard OAuth delegation rather than introducing a new one. Concretely, an orchestrator that receives a board-packet Mission and spawns a sub-agent to handle number reconciliation has delegated a slice of the parent Mission. The child's authority should be the parent's read-and-compare envelope for finance systems, and nothing else. ```text +------------------+ | Mission state | | owner | +------------------+ | | | +--> Trust quality | assessment | | | v | +------------------+ | | Budget policy | | | tighter at hop | | +------------------+ | | v | +------------------+ | | Parent Mission | | | full envelope | | +------------------+ | | | +--> attenuated | authority | | | v v +----------------------+ | Child Mission | | finance read-compare | +----------------------+ | v +----------------------+ | Enforcement points | +----------------------+ ``` But that is not the only issue. Delegation also changes governability. A child agent may: - run in a different runtime - expose weaker telemetry - use different tool adapters - have poorer provenance guarantees The delegated authority may be narrower on paper and still be less governable in practice. This means delegation must attenuate trust assumptions, not just authority bounds. Child Missions may need tighter budgets, stricter callbacks, or less autonomy simply because visibility and control quality are worse at that hop. The mechanism for this attenuation should be explicit. The Mission state owner should assign a trust quality level to each hop based on observable signals: whether the child runtime emits verifiable tool-call provenance, whether telemetry is independently observed at a boundary rather than self-reported, and whether the child Mission has an established behavioral baseline or is operating cold-start. A child with low trust quality receives a more conservative budget policy and stricter callback thresholds regardless of whether its authority bounds are otherwise equivalent. A harder case is spontaneous delegation: an orchestrator spawning a sub-agent at runtime without any prior human delegation event. This is common in practice and hard to govern cleanly. The Mission state owner must still issue child authority, but who triggers that issuance when the spawn is an autonomous runtime decision rather than a pre-authorized step? Without an answer to this, spontaneous sub-agents fall outside the governance model and effectively operate in the headless case, without the provenance hierarchy that headless governance requires. This is also where requester context has to survive the delegation chain. If child agents cannot inherit and present the right task context at each hop, even well-bounded authority models become hard to evaluate consistently. ## Headless Missions In headless cases, no human is present to verify the proposed Mission. That means deterministic shaping is not enough. You also need authority provenance. A scheduled nightly reconciliation agent operating from a standing organizational policy with no user present is the canonical headless case. What is being shaped? - an organizational policy - a runbook - a prior approved Mission - a service owner's standing delegation Those are not interchangeable sources of legitimacy. So headless governance needs: - machine-verifiable shaping rules - machine-verifiable provenance for the authority source being shaped If the provenance source cannot be independently verified by the Mission state owner without relying on the agent's own claims, it is not a headless governance anchor. Valid provenance sources are not interchangeable. In descending order of legitimacy: - A prior human-approved template Mission: a human already confirmed this shaping output is acceptable for this task class. - A standing organizational policy expressed in a formal, auditable policy language. - A service owner's cryptographically verifiable standing delegation. What does not qualify: LLM inference about organizational intent, runtime configuration supplied by an agent or orchestration layer at execution time, or a general-purpose scope grant that predates the specific task. This legitimacy hierarchy is canonical for any Mission โ€” not only headless ones. [The Mission Model's Consent property](/notes/the-mission-model/#what-a-mission-is) formalizes the valid and invalid anchors as part of the Mission primitive itself. Headless governance keeps the same authority anchor requirement as human-present governance. It just moves provenance verification to the machine. The next failure mode shifts from no human to no stable authority state at all. ## Resumption Suspension is not necessarily terminal for long-running enterprise workflows. A Mission interrupted by an anomalous action may need to resume once a human has reviewed what happened. But resumption is not the same as re-approval of the original Mission. The state has changed. Some reversible actions may have occurred. The trust budget has a consumption history. A governable resumption model therefore needs: - persistent execution state at suspension time - a resumption decision that sees that state, not just the original intent - trust budget continuity rather than full reset Mission termination mid-execution also raises a distinct sub-problem: compensating or rolling back partial state from actions that have already completed. That is a workflow concern, but the governance layer must coordinate with it. A terminated Mission's authority does not undo side effects that have already propagated. This is another place where the architecture starts to look less like IAM and more like a workflow governance control plane. Durable execution state across suspension events, compensating actions for partially completed workflows, and governed resumption with inherited context are patterns from durable execution systems in workflow orchestration, not from traditional IAM. That boundary crossing is not accidental. Mission governance for long-running agents needs to borrow from both disciplines. IAM without workflow state is insufficient for multi-stage tasks. Workflow orchestration without authority governance is insufficient for delegated, externally observable agents. The architecture that emerges from taking both seriously is neither a pure IAM system nor a pure orchestrator. That architectural breadth has a cost. Running this control plane at enterprise scale means policy owners to govern templates, operators to review expansions and resumptions, telemetry pipelines that can support trusted observation, and engineering teams willing to absorb friction in exchange for bounded risk. Any serious argument for this architecture has to be honest about that operational burden. Each of these failure modes is a form of survivable incorrectness in practice. The architecture cannot prevent scope creep entirely, cannot eliminate spontaneous delegation, cannot guarantee headless provenance, and cannot make resumption seamless. What it can do is bound the damage from each: staged authority limits quiet expansion, trust quality attenuation limits the radius of a delegated failure, headless provenance hierarchies establish accountability chains even without a human present, and resumption requirements prevent stale authority from being silently reactivated. The goal is not a control plane that never fails. It is one that fails in bounded, detectable, and recoverable ways. # The Interoperability Problem Each of the limits above operates within a single organization: shared purpose taxonomy, known systems, and a single Mission state owner. Cross-organizational deployment introduces complications the single-org model cannot absorb. Mission authority shaped in one trust domain cannot be evaluated semantically in another, even when the transport format is identical. If two organizations deploy agent systems independently, each with their own purpose taxonomy and shaping logic, a Mission created in one cannot be meaningfully evaluated in the other. The `mission_ref` is portable. The semantics it encodes are not. Interoperability requires more than a purpose taxonomy. It needs shared meaning for: - resource classes - action classes - canonical subject and object identifiers - selector and constraint semantics - attenuation and expansion rules - parent-to-child derivation rules Without those, a "portable authority representation" is just a transport container for incompatible local meaning. This identity resolution layer is easy to understate, and it is often where enterprise deployments actually break. "Board packet", "final numbers", "Q1", and even the CFO's own authority scope may resolve differently across finance systems, content repositories, and messaging tools. Adjacent standards work helps with plumbing, but not with semantic authority: - OAuth RAR (RFC 9396) provides a richer authorization request format than scopes, allowing structured authorization detail in the request itself. It is the closest existing standard to a Mission authority carrier. But RAR is a request language, not a shaping substrate; it still requires the semantic work to be done before the request is formed, and it does not govern the Mission lifecycle after issuance. - Policy engines such as OPA and Cedar help express and evaluate policy once the world has already been reduced to stable resources, attributes, and actions, but they do not solve the shaping step that produces those stable inputs from natural-language intent. The interoperability problem still points back to a missing semantic layer for Mission shaping. RAR and token formats can carry authority. They do not supply the shared task semantics that make that authority interoperable. # What Containment Adds In open-world environments, containment has to carry safety properties that Mission shaping cannot provide. Containment means: - narrow discovery envelopes by default - strong tool mediation and trusted adapters - short-lived, attenuated credentials - boundary observation that does not rely on agent self-report - irreversible actions gated by callbacks, checkpoints, or explicit human release - runtime isolation strong enough that a compromised agent has limited room to act A tool call, as used here, means any invocation to an external system through an adapter: file reads and writes, API calls, browser navigation, code execution, and message dispatch. Every such call is a potential observation and enforcement point. Containment is meaningful only if the tool mediation surface is consistently enforced. A single unmediated path through a privileged adapter negates the rest. [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is one framework for tool mediation at this layer. [IBAC](https://ibac.dev/ibac-paper.pdf) demonstrates one concrete implementation of the enforcement boundary itself: a higher-order `invokeToolWithAuth` wrapper that every tool call must pass through, with no path around it. The wrapper checks the request against the intent-derived authorization store before execution; unauthorized calls are denied before they reach the tool. Whether using MCP, a proprietary adapter pattern, or an enforcement wrapper of this kind, the architectural requirement is the same: tool calls must flow through a boundary that can enforce authority constraints, log call provenance, and interrupt on anomaly without relying on the agent to report its own behavior accurately. But tool mediation alone is not enough. A gateway can enforce requests and still lack the deeper runtime context needed to judge intent well. Direct integration with underlying systems can provide richer behavioral visibility and still lack decisive control. Runtime governance needs both: enforcement points that can block and trusted observation points that can explain why a given action is risky. Agent containment differs from standard defense-in-depth in its threat model. Traditional defense-in-depth assumes threats arrive from outside the perimeter and that authenticated actors are trusted. Agent containment inverts that assumption: the threat is authorized misuse by the agent itself, with correct credentials but misaligned or injected intent. The attack surface is the agent's context window, not network ingress. The goal is semantic integrity across the agent's execution, not perimeter security at the organizational boundary. [NIST SP 800-207 (Zero Trust Architecture)](https://csrc.nist.gov/publications/detail/sp/800-207/final) provides the foundational framing: no implicit trust based on network location or credential possession, continuous verification of each request. Agent containment extends ZTA's microsegmentation principle to the agent's execution environment, treating each tool call as a request to be evaluated rather than trusting the agent to police its own behavior inside a broad authority grant. [NIST AI 100-1 (AI Risk Management Framework)](https://airc.nist.gov/RMF) places this in the broader governance context: the Mission shaping and containment controls described here are the authorization-layer instantiation of AI RMF's govern, map, measure, and manage functions for agentic AI systems. This is not an alternative to Mission governance. It is what makes Mission governance survivable when the semantic layer is incomplete. Mission shaping gives you declared purpose, reviewable approval, and auditable authority boundaries. Containment gives you bounded blast radius, safer behavior when the semantics are wrong, and more reliable interruption when drift is detected. Containment has costs. Tool mediation adds latency on every call. Callback gates for irreversible actions introduce availability dependencies. Narrow credentials create friction for legitimate scope expansions. There is also a staffing cost: someone has to configure and monitor the containment layer, triage pause events, and respond to budget exhaustion at runtime. Neither Mission shaping governance nor containment governance is free to operate. Treating containment as a first-class design decision means making these tradeoffs explicitly rather than discovering them under production load. For open-world agents, containment is the more important layer. # When To Rely On Each Containment is not a fallback activated when Mission shaping fails. The two layers are co-equal. The right balance depends on deployment context. There are signals that indicate which layer needs to carry more weight. **Mission shaping is stronger when:** - The domain is structured and the task class is well-defined (board packet preparation, not "do research") - The systems involved are known and enumerable at approval time - The agent operates within a single organizational trust domain - There are observable, gated transition points between reversible and irreversible phases - The control plane can tolerate approval friction for stage transitions **Containment is more important when:** - The environment is partially observable (the control plane cannot independently verify what tool calls the agent is making) - The agent may encounter external content it did not generate and cannot be fully trusted not to act on - The task involves cross-domain or cross-organizational boundaries with incompatible shaping semantics - The agent's telemetry is self-reported rather than independently observed - Failure needs to be survivable regardless of whether the semantic model is correct [The IE zone model](/notes/the-mission-shaping-problem/#a-historical-parallel) is a useful map. Local Intranet corresponds to the structured case: known systems, organizational trust domain, observable transitions, controllable policy. The Internet zone corresponds to the containment-primary case: unknown origins, uncontrollable external content, incompatible semantics, weak observability. Most agent deployments sit somewhere between them, which is exactly where IE zone policy was hardest to get right. The IE lesson about defaults applies directly: the right default for an unclassified agent task is the most restricted posture. Not "figure out what this task probably needs and grant approximately that." The default is minimum authority, and the organizational process should be to elevate by governed exception with documented justification, not to restrict by exception from a broad default. Getting the default wrong is how Trusted Sites fills up. The two examples in this series illustrate the poles. The CFO board-packet task is the structured case: one enterprise, known systems, structured approval path, legible stages. A shaping-centered architecture with staged compilation, governed expansion, and callbacks is tractable. The vendor research task ("research vendors, summarize options, and begin outreach where appropriate") is the containment-primary case: open-ended scope, external content at every step, ambiguous action boundaries, no way to fully enumerate the authority model upfront. Mission shaping still provides a governance record and outer bounds, but the real safety properties come from mediated outreach, short-lived credentials, sandboxed browsing, and explicit release gates before any external communication is sent. Most real deployments fall somewhere between the two poles. The practical answer for an enterprise finance workflow is: lead with staged Mission shaping for structured phases, often implemented as staged compilation, and surround it with containment controls that keep the blast radius bounded if the semantic model turns out to be wrong. For open-world tool-using agents with no known execution path in advance, lead with containment and treat Mission shaping more as a governance record than as a safety guarantee. Both layers still leave a residual problem: an agent can stay within its Mission authority envelope while drifting away from the user's intent. A runtime layer is needed to detect that drift and act on it before it compounds. # Runtime Alignment: Trust Scores and Budgets If Mission shaping defines the declared authority ceiling, runtime trust defines how much residual uncertainty the system is willing to tolerate inside it. What follows is one practical control-plane pattern, not a settled standard. Continuous observability is not governance, but it is the runtime evidence layer that makes behavioral analysis and dynamic intervention possible. ```text +----------------------+ | Mission authority | | envelope | +----------------------+ | v +----------------------+ | Agent actions | +----------------------+ | v +----------------------+ | Observability | | signals | +----------------------+ | v +----------------------+ | Trust budget | +----------------------+ | v +----------------------+ | Pause / callback / | | suspend | +----------------------+ +----------------------+ | Containment | | boundaries | +----------------------+ | +--> constrain actions +--> enforce stops ``` This should be understood as part of the same control plane, not as a second hidden policy engine. The Mission authority artifact remains authoritative for what the Mission permits. The runtime trust layer does not expand authority. It only decides whether the system is still willing to rely on the agent's local judgment within already-shaped bounds. Even conceptually, that assumes a lot from the underlying system. To score runtime alignment, the control plane needs structured tool calls, stage context, parent Mission linkage, and normalized provenance about where the action came from. Most enterprises do not have that by default, and the visibility gap varies by agent type. Homegrown agents expose different control surfaces than SaaS agent platforms or local workstation agents, and locally run tools are often the hardest for enterprise controls to observe reliably. And visibility is not enough. If the agent runtime, orchestration layer, or tool adapter can freely invent the telemetry that the trust layer depends on, the system has recreated self-governance one layer down. Runtime alignment needs integrity as well as visibility. Telemetry must be attributable to a verifiable source, not taken on the agent's word. [SPIFFE/SPIRE](https://spiffe.io/) workload identity provides one foundation: cryptographic attestation of which runtime component produced a given report. [CAEP (Continuous Access Evaluation Protocol)](https://openid.net/wg/sse/) and the Shared Signals Framework provide the transport: a standardized event stream for runtime security events flowing from the components that observe them to the Mission state owner that needs to act on them. Without both integrity and a signal pathway, the runtime alignment layer either trusts what agents report about themselves or polls blindly. The right model treats residual runtime trust not as binary, but as a continuously scored, consumable resource. The pattern is [just-in-time trust](https://softwareanalyst.substack.com/p/the-future-of-just-in-time-trust) applied to Mission lifecycle. The system grants only the minimum authority needed at the moment it is needed and reconfirms rather than assumes continuity across the task's execution. Recent runtime-governance work, including [MI9](https://arxiv.org/abs/2508.03858), converges on a similar point: semantic telemetry, continuous authorization monitoring, drift detection, and graduated containment become necessary once agent behavior cannot be fully governed at approval time. Each agent action is evaluated against a weighted intent score: does this align with the approved intent? Is it consistent with the agent's established pattern for this task? How much damage if it results from context taint? How much of the Mission window remains? A low intent score on a high-risk action is grounds for pausing and requiring re-confirmation even when the action falls within the Mission authority envelope. Each Mission carries a consumable trust budget. Actions that score low on intent alignment consume budget faster. Actions anomalous relative to the behavioral baseline consume faster still. Budget exhaustion triggers re-confirmation or Mission suspension. Budget state belongs with the Mission state owner. Exhaustion is a lifecycle event, not a side-channel signal. Practical calibration needs a signal model, a baseline, and a cold-start policy. Useful observable signals include resource type distribution relative to the declared purpose, rate of external communication attempts relative to task phase, and semantic similarity of each action to prior approved executions of the same task class. The baseline for a given task class is most reliably established from reviewed template Missions. Prior human-reviewed executions define the expected action distribution that a new run is scored against. The cold-start problem has no clean solution. A reasonable default is to open with the strictest callback thresholds in the relevant template class and relax the budget as an execution baseline accumulates. Semantic drift detection is the operational form: monitoring whether the agent's actions are drifting from the semantic neighborhood of the approved intent. A board-packet preparation Mission should produce mostly reads, comparisons, and internal assembly operations. If the action log starts showing HR system reads, treasury queries, or external communication attempts, the distribution has shifted outside the expected neighborhood for this purpose class even if each individual call was permitted. The governance boundary is precise. Shaped authority is authoritative for permit and deny decisions. Trust scores are authoritative for pause, callback, and suspension decisions. Trust scores do not expand Mission scope. A trust budget is not additional privilege. It is a continued-reliance threshold for exercising already-shaped authority. This is closer to risk-adaptive and continuous-evaluation control than to entitlement expansion. > The shaped Mission Authority Model answers "is this action permitted?" The trust layer answers "is the system still willing to rely on this agent's judgment while it does it?" Staged Mission shaping and trust budgets interact. A Stage 1 discovery envelope carries lower inherent risk (the agent cannot write, publish, or communicate externally), so the trust budget can be calibrated more permissively. When the Mission transitions to Stage 2, the budget policy should tighten: the same semantic drift tolerable during read-only discovery becomes a higher-stakes signal during write-capable execution. The Mission state owner issues a revised budget policy alongside the revised authority artifact at each stage transition. Trust scoring is probabilistic, not deterministic. A sophisticated adversary may craft injected instructions that score well on intent alignment. The behavioral baseline must be established before drift can be detected, creating a cold-start problem. The scoring model itself becomes an attack surface. These limitations are real. The value of this layer is not certainty. A governed control plane that can act on partial confidence and bounded suspicion is more honest than one that pretends runtime alignment is either fully knowable or irrelevant. # Design Positions The following positions have defensible answers. Each has a live counterargument worth naming. The first two concern Mission shaping directly; the last two concern containment and the runtime layer explored in this part. **LLM-based Mission shaping is acceptable as a proposal step, but should not be the sole authoritative one in high-assurance systems.** The counterargument is that human review of a structured proposal does not actually close the verification gap: if the CFO cannot evaluate the compiled artifact, reviewing the LLM proposal does not help either. That objection is correct about the limits of review, but it argues for better review tooling (progressive disclosure, natural-language summaries of effective permissions), not for removing the human approval step. The LLM proposes. The authorizing system approves. The Mission state owner locks the result. Treating unconstrained LLM output as the authority artifact without that review is inference masquerading as authorization. **Mission shaping belongs with the Mission state owner, not in the agent.** The counterargument is that the orchestration layer already owns execution state and is better positioned to perform shaping incrementally. That is architecturally attractive but it conflates semantic authority with execution management. If shaping lives in the agent or orchestrator, it is self-governance. The system of record for Mission state should own the authority artifact, staged expansions, and the runtime signals that can suspend or terminate it. **Confirmation thresholds for irreversible actions should be risk-based, not permission-based.** Whether an action falls within the Mission authority envelope is the wrong question for high-stakes decisions. The right question is whether the action is irreversible and whether the risk magnitude justifies a human checkpoint regardless of authorization status. Financial transactions above a threshold, permanent data deletion, external communications on the user's behalf: these warrant re-confirmation even when they are within authority bounds. **Containment controls should be first-class design decisions, not deployment accidents.** Most deployments have some containment by accident. Treating containment as an intentional layer (deciding which tool calls are mediated, what credentials are issued, and which boundaries are independently observed) is a different and more defensible posture than hoping accidental constraints are sufficient. # Open Questions These questions span both parts of the series. **Mission shaping** - What is the minimum viable purpose taxonomy for common agent use cases, and who defines it? - Can Mission shaping be made deterministic enough to govern without losing the expressiveness that makes natural language intent useful? - What does a verification UI look like that achieves better bounded comprehension without overwhelming the approver? - Who can authorize a stage transition, and what mechanism prevents an agent from self-promoting to the next stage? - At what point do accumulated expansion decisions make the executed authority model so different from the originally shaped one that the original approval no longer meaningfully covers the activity? This boundary defines when re-approval is required rather than another governed expansion; the architecture currently has no answer for it. **Authorization and enforcement** - What is the developer-facing API for agent teams to propose Missions, receive a Mission Authority Model, request expansions, and report telemetry? The governance model is described from the operator perspective; the agent side of the interface is not. - How does Mission governance retrofit onto orchestration frameworks (LangGraph, CrewAI, AutoGen) that already create child agents in production without Mission authority? What is the integration surface? - What is the right composition between enforcement-point-level authorization (IBAC or CaMeL style at the tool boundary, ASTRA style at token issuance) and Mission-level shaping? Are these complementary layers in the same control plane, or competing designs that reflect different threat models? **Runtime alignment** - How should trust budgets be sized and calibrated for different task classes? - Can trust scoring resist adversarial optimization by an attacker who understands the scoring model? - What is the right cold-start policy when no behavioral baseline exists for a new agent or task class? **Interoperability** - Is cross-organization authority portability achievable, or is it always federation with semantic gaps? - Which task verticals are positioned to define domain-specific purpose taxonomies first? **Control-plane architecture** - Where should the Mission control plane boundary actually sit: inside the authorization server, in a separate authority service, or partially inside the orchestrator that already owns durable execution state? - What is the governed failure mode when the Mission state owner is unavailable during an active Mission? An active execution that reaches Stage 2 while the Mission state owner loses quorum will continue honoring stale Stage 1 tokens at enforcement points; this is not a hypothetical edge case. # The Deeper Problem The field is treating governance problems as engineering problems. Better token formats, tighter delegation chains, more expressive policy languages. Standards bodies are good at this work. But the protocol layer assumes the hard Mission shaping work is solved upstream. It is not. Some adjacent proposals, such as [Authenticated Delegation and Authorized AI Agents](https://arxiv.org/abs/2501.09674), try to solve more of the problem at the delegation and credential layer by emphasizing authenticated delegation, agent-specific credentials, and auditable chains of accountability. Those are useful contributions. They still do not remove the need for Mission shaping, because binding a delegation chain to an agent does not by itself tell the system what bounded authority should exist for the task in the first place. The systems that come closest to solving the enforcement problem are each explicit about this gap in their own limitations sections. IBAC's model is scoped to a single request and a single agent; it does not address multi-agent delegation or long-running missions that span many requests. CaMeL handles data provenance within a single execution but not across delegation hops. The ASTRA work on semantic task-to-scope matching acknowledges directly that "applying delegated authorization in this way across chains of agents demands mechanisms for preserving requester context" that the approach does not yet provide. The gap this series addresses is not a gap the field has missed. It is a gap the field's best current work has named and left open. > You can have a perfectly specified [Mission-Bound OAuth](/notes/mission-bound-oauth-architecture/) deployment with a `mission_ref` on every token, lifecycle management at the AS, and verified actor continuity across every hop. And still have no idea whether the agent is operating within the bounds the user actually intended. The conclusion is not that compilation is useless. It is that compilation is one disciplined form of Mission shaping, and Mission shaping alone is insufficient, whether formal or informal, without containment. Containment is not a fallback. It is the co-equal operational resilience layer. Better Mission shaping is necessary for structured domains where the task class is well-defined and semantic fidelity is achievable. Containment is equally necessary in open environments where the semantic model will always be incomplete. Mission governance requires both, and architectures should be explicit about which layer is carrying the weight in any given deployment. The Mission shaping record also has a governance value independent of its safety properties. The Approved Mission is the prerequisite for meaningful audit: without a declared governance record of what was supposed to happen, the system cannot determine whether what happened was authorized, who approved it, and on what basis. In regulated environments where agent actions affect financial records, health data, or external communications, that audit prerequisite is not optional. Mission shaping may not prevent all misalignment. But it is the only mechanism that produces a reviewable approval object that post-hoc investigation can compare against the actual execution record. The operational goal is survivable incorrectness: a control plane that can remain governable and limit damage even when the semantic model is partial, noisy, or wrong. Perfect semantic fidelity is not achievable at the scale and openness of real agent deployments. Survivable incorrectness is. Deployment posture also depends on where the organization sits on the human approval spectrum. In practice there is a range: fully automated, human-on-the-loop (reviews batches), supervised autonomy (can interrupt), human-in-the-loop (approves each step). Where an organization sits on that spectrum directly determines how much Mission shaping and how much containment the deployment requires. That calibration is an organizational policy decision, not a protocol question. That also narrows some of the design uncertainty. The overhead of formal Mission shaping is justified first for structured enterprise workflows with stable systems, legible approval points, and tolerable governance friction. In those domains, Mission shaping may take the form of explicit compilation. In the middle ground between full upfront planning and containment-first execution, the more realistic target is bounded adaptation: the agent can discover, propose, and adjust, but only inside a staged Mission envelope with governed expansion and runtime checkpoints. For open-world tool-using agents, organizations should expect to lead with containment and treat Mission shaping more as a governance record than as the primary safety guarantee. In some task classes, that should be an explicit policy decision: choose containment-first governance rather than waiting for semantic shaping to mature, because survivability matters more than semantic richness. In other cases, the right policy may be stricter still. Do not allow the task to run agentically at all until the runtime is sufficiently contained and the blast radius is acceptable. The evidence so far also suggests that a shared semantic layer for shaped Mission authority is more likely to emerge as domain-specific families than as one universal model for all agent behavior. That is a more demanding view of what agent authorization requires. It is also the more operationally honest one. --- # The Mission Shaping Problem Canonical URL: https://notes.karlmcguinness.com/notes/the-mission-shaping-problem/ Markdown URL: https://notes.karlmcguinness.com/notes/the-mission-shaping-problem.md When a CFO asks an agent to assemble the board packet, reconcile the final numbers, and call back for approval before releasing the presentation, they are not specifying an access control list. They are expressing intent. Something has to turn that intent into something a control plane and its enforcement points can evaluate. That conversion is the Mission shaping problem. In the vocabulary of this series, human intent becomes a [Mission Proposal](/notes/mission-bound-oauth-architecture/#key-terms). Human approval turns that into an [Approved Mission](/notes/mission-bound-oauth-architecture/#key-terms). The control plane materializes that as a [Mission Authority Model](/notes/mission-bound-oauth-architecture/#key-terms). Enforcement points see the resulting authority artifact. Mission shaping does not replace policy engines, PDPs, PEPs, token services, or authorization servers. It sits upstream of all of them and produces the task-bounded authority artifact they need to make coherent decisions for agentic work. Many current deployments do not have a disciplined Mission shaping step. The agent gets a token with broad scopes, infers its own boundaries from context, and the system trusts it to stay within them. That is not governance. That is optimism. This article focuses on LLM-driven, tool-using agents executing multi-step tasks. This is the deployment class where Mission shaping is hardest, the blast radius is largest, and the governance gap between current practice and what safety requires is widest. But there is a harder conclusion visible even within that argument. Even if deployments had a rigorous Mission shaping step, shaped authority alone would still not be enough for open-world agents. Mission shaping is the semantic anchor. Containment is the operational resilience layer that has to carry the safety margin when the semantic model is incomplete. Containment means designing the agent's operating environment so that a failure, compromise, or misaligned action has bounded blast radius through narrow credentials, mediated tools, trusted observation points, and explicit release gates. So the real question is not just how to shape a Mission from approved intent. It is where the semantic layer is strong enough to bear the weight, and where containment has to carry more of it. > The gap between what a user approves and what a system can govern is not a configuration problem. It is a semantic one. But semantic problems do not disappear just because you shape them into a more structured artifact. Mission shaping still matters. It gives the system a declared purpose, a bounded authority artifact, a reviewable approval object, and an auditable explanation of what the task was supposed to be. In structured domains, that shaping can take the form of compilation. But containment is what keeps the system safe when the semantic model is incomplete, the runtime is partially observable, or the agent's behavior drifts inside nominally legitimate authority. This essay picks up a question left open by [Part 4](/notes/why-mission-bound-oauth-might-be-the-wrong-answer/) of the [Mission-Bound OAuth series](/series/mission-bound-oauth/). # A Historical Parallel The browser world navigated a structurally similar problem a generation earlier. Its failure modes are the closest historical precedent for where agent authorization is now. In the late 1990s, browsers became the first mainstream open-world agents. A browser could navigate anywhere: internal intranet resources, trusted enterprise applications, and the open internet. Each environment carried different risk. Organizations needed a way to let employees use the browser productively without giving the open internet the same authority as internal systems. Internet Explorer's answer was security zones. Local Intranet, Trusted Sites, Internet, and Restricted Sites each had a default capability envelope: what scripts could run, what plugins could load, what downloads were permitted. Administrators could assign URLs to zones via Group Policy and configure zone-level policy centrally. The mapping to agent authorization is direct: - Security zones are authority envelopes. The Internet zone is the minimum-authority default for unknown intent. Trusted Sites is the enterprise template Mission for known, pre-approved task classes. - Zone assignment is the classification step. Deciding that a URL belongs in the Intranet zone is the same problem as deciding that "assemble the board packet" belongs in the "structured enterprise workflow" authority class. - Group Policy zone configuration is organizational Mission shaping governance. The admin defining what the Internet zone can and cannot do is the admin defining a purpose taxonomy. - The default Internet zone posture is the minimum authority principle. Unknown origin, most restricted envelope. Elevate by organizational exception with documented justification. The browser world also learned the failure modes: - Everything ends up in Trusted Sites. Every enterprise application that did not work in the Internet zone got added to Trusted Sites because that was easier than fixing the application or narrowing the zone policy. Templates accumulate exceptions for the same reason. - Zone classification alone was insufficient. Modern browsers do not rely primarily on zones. Process-level sandboxing, Content Security Policy, CORS, and same-origin policy are the actual safety mechanisms. Classification is still there, but containment became the primary layer. - The escalation mechanism is the attack surface. Users who could manually add sites to Trusted Sites were a persistent governance failure. Agents that can quietly self-promote their authority class are the same failure. The analogy also shows where agent authorization is harder. URL classification is syntactic: string matching against a domain or pattern. Intent classification is semantic: natural language, open-ended, context-dependent. That difference is not incidental. It is the source of most of what makes agent authorization hard in ways that URL-based zone models never had to confront. Authority is also time-varying in a way zones never were. A URL stayed in its zone. A Mission Authority Model changes as the task progresses from discovery to execution to external release. The staged, versioned Mission shaping model has no zone equivalent. That is one reason the zone model, however well adapted, cannot be sufficient by itself. The threat model is inverted. IE's zone model protected the user from external content attacking through the browser. The agent's context integrity problem is the agent using its own legitimate authority in service of external adversarial content it encountered mid-execution. Containment therefore needs to operate differently: not just at the boundary between the agent and external systems, but also on what the agent can do after it has processed external content. Organizations need some mechanism to manage risk while gaining the benefits of open-world agents. The zone model is the right structural intuition: classify intent into authority classes, apply default-restrictive policy, elevate by governed exception. The browser world shows that this is a necessary first step and an insufficient final answer. Containment is what made browsers survivable at scale, and containment is what will make open-world agents survivable too. # What Mission Shaping Means Here The compiler analogy is useful for describing one version of the job, less useful for describing the full problem. In software, a compiler transforms a formal language with defined semantics into machine-executable instructions. Mission shaping is broader. It is the work of taking a high-level approval and producing something the Mission control plane and its enforcement points can apply mechanically across API calls, tool invocations, and delegation boundaries. In the structured case, Mission shaping can take the form of explicit compilation. In the more open case, the shaping layer is less formal: a bounded purpose statement, a set of allowed tool classes, and an operating envelope rather than an enumerable action list. That coarser output still provides the governance anchor (the approved authority artifact that the control plane and containment layer can reference) even when it cannot enumerate every permitted action. What changes across cases is precision, not the requirement for an artifact. The structured-case pipeline looks like this: ``` Human intent โ†“ Mission Proposal โ†“ Approved Mission โ†“ Mission Authority Model โ†“ Enforcement ``` Each step is a transformation. Each transformation is a place where meaning can be lost, distorted, or never captured. That is the core Mission shaping problem. # A Four-Layer Model Agent authorization is easier to reason about if four distinct concerns are kept separate. From an IAM perspective, the separation is straightforward. Identity answers who is acting. Mission shaping answers what authority should exist for the approved task. Authorization answers whether a requested action is inside that authority. Workflow and runtime governance answer whether execution should continue under current conditions. In the vocabulary of the XACML and NIST policy model, the Mission state owner corresponds to the Policy Administration Point (PAP). It authors, versions, and lifecycles the authority artifact. Enforcement points at API and tool boundaries are Policy Enforcement Points (PEPs). The authorization layer is the Policy Decision Point (PDP). Runtime alignment has no direct equivalent in the traditional PAP/PDP/PEP decomposition and belongs to the usage-control tradition discussed below. | Layer | Question | Output | Who | |---|---|---|---| | Mission shaping | What authority should exist for this approved task? | Authority artifact: Mission Proposal, Approved Mission, and Mission Authority Model in structured domains; a bounded purpose record and operating envelope in open-world cases | Mission state owner | | Authorization | Is this specific action inside that authority? | Permit, deny, step-up, or suspend | Enforcement points at API and tool boundaries | | Containment | If the authority model is wrong, incomplete, or bypassed, how much damage is possible? | Bounded blast radius through narrow credentials, mediated tools, runtime isolation, and explicit release gates | Enforcement architecture, gateways, trusted adapters, and runtime boundaries | | Runtime alignment | Even if the action is allowed, is the agent still acting in service of the approved intent? | Continue, pause, re-confirm, or terminate | Mission state owner governing lifecycle decisions, fed by distributed observation points such as gateways, tool adapters, and trusted telemetry sources | Mission shaping creates the authority artifact. Authorization checks whether a call is inside its bounds. Containment bounds the damage if the artifact is wrong, incomplete, or bypassed. Runtime alignment detects the residual risk that remains even when each individual call is technically permitted. That last layer matters because LLM-driven agents can be corrupted by prompt injection or context taint while still operating inside legitimate authority. Mission shaping defines the ceiling. It does not guarantee the agent is still acting in service of the user's intent. The semantic challenge of getting that layer right is the Mission shaping problem. Compilation is one disciplined form of Mission shaping, strongest in structured domains and insufficient in most open ones. The more open the environment becomes, the more the architecture has to lean on containment. The goal is not a system that is always semantically correct. It is a system that remains governable when the semantic model is wrong: survivable incorrectness rather than an unachievable semantic guarantee. The family resemblance to continuity-of-use or usage-control thinking is intentional, including the UCON tradition (Park & Sandhu, 2004). Authority should not be treated as a one-time admission decision, but as something that remains subject to ongoing conditions while the task continues. Agents make that continuity problem harder. The system is not only asking whether a session should continue, but whether an adaptive, tool-using, partially observable actor should continue under the same authority envelope. The trust scores and budgets introduced in [Part 2](/notes/mission-shaping-is-not-enough/) are one operational form of that continuity principle. UCON was technically coherent but never achieved deployment at scale. The enforcement infrastructure required to act on continuous conditions simply did not exist in 2004. What is different now is that LLMs make natural-language intent tractable as an input to authorization systems, the zero trust and workload identity infrastructure exists as a practical enforcement layer, and regulatory pressure to govern autonomous system behavior is pushing organizations to take runtime authorization seriously in a way that has no parallel in the UCON era. # Why Mission Shaping Is Hard ## Semantic Ambiguity Natural language intent is inherently ambiguous. "Assemble the board packet and call me back before release" could authorize pulling draft forecasts, reading prior board materials, reconciling finance data, contacting the FP&A system, or notifying the legal team that a release is pending. Or it could authorize only gathering materials and presenting a summary for review. What gets approved is rarely just what the user asked for. In enterprise systems it is usually a constrained intersection of requested purpose, system design, business role, and organizational policy. The shaping step has to convert that ambiguous intent into something a resource server can evaluate deterministically. In the structured case, that means a compilation step. Either way, it requires a purpose taxonomy: a shared vocabulary for what "board packet preparation" means in terms of actual API operations and data access. No such shared taxonomy exists. Every implementation invents its own. The failure pattern this creates is familiar from RBAC role explosion and ABAC attribute normalization. Both required organizations to maintain shared vocabulary mappings that accumulated exceptions, became inconsistently applied, and expanded past what any single team could govern. A purpose taxonomy for agent tasks follows the same organizational dynamics. The taxonomy is also a governance artifact: it encodes organizational policy into machine-evaluable terms and is subject to its own scope creep, organizational drift, and capture by convenience. Who governs the purpose taxonomy itself is a question the architecture must answer. [OpenID AuthZEN](https://openid.net/specs/openid-authzen-1_0.html) is an approved OIDF standard for the PEP-to-PDP query interface. It standardizes how enforcement points ask for authorization decisions once subject, resource, action, and context are already structured enough to evaluate. Mission shaping is the step that produces those stable inputs. For open-world LLM-driven agents, the resources may not be enumerable at policy-writing time, the attributes may not map cleanly to natural-language intent, and the policy for a novel task class may not exist at all. AuthZEN and downstream policy engines still require that upstream work to be done. ## The Verification Problem Even if you have a Mission shaping step, how do you verify that the resulting authority model represents what the user actually approved? With code, a compiler translates a formal language with defined semantics. You can inspect the output. You can write tests. You can formally verify properties of the compiled artifact. With intent, you are translating natural language. The input has no formal grammar. The compiler has no type system to catch semantic errors. The authorizing user cannot inspect the Mission Authority Model in any meaningful way. They approved something in human terms. The compiled artifact is in machine terms. The mapping between them is opaque. > A CFO who approved "assemble the board packet and call back before release" has no way to verify that the compiled authority model does not also permit the agent to access unrelated HR records, treasury operations, or investor communications, if the purpose taxonomy the system uses is broader than they understood. The verification gap is not theoretical. It is the difference between informed consent and a terms-of-service checkbox. You can reduce that gap with better UX: - a natural language summary generated from the compiled artifact rather than the original proposal - progressive disclosure of the effective permission envelope - callback points for the highest-consequence transitions - a consent receipt that records what the user actually approved But complex enterprise workflows quickly exceed what an approving human can meaningfully reason about from a summary. So the real goal is not perfect human comprehension. It is better bounded comprehension. The gap also worsens as adoption scales. The first task templates are reviewable by a careful operator. After a purpose taxonomy grows to hundreds of templates with layered pre-approved expansion paths, verifying that any specific compiled output correctly represents the original approval intent becomes progressively less tractable. Organizations that use the architecture most heavily face the worst verification fidelity, exactly backwards from what a governance model should produce. ## The LLM Trust Problem Many deployments that do have a shaping step use an LLM to perform it. That is a practical approach. It is also a governance problem. The first point of adversarial influence is wherever the Mission Proposal is generated: whether that is the agent itself, a form-to-proposal translation layer, or an orchestration system. An LLM-based compiler is not deterministic. The same intent statement can produce different authority models on different runs even in the absence of adversarial input. It can also be influenced through the prompt. It has no formal semantics. And its output is the input to your enforcement system. That matters even before you get to prompt injection. If two benign runs produce materially different authority envelopes, reproducibility, operator review, and audit all become unstable. Prompt injection makes that worse. For high-assurance governance, LLM-first Mission shaping should therefore remain a proposal step wrapped by bounded review and approval, not the sole authoritative step. One architectural response is to narrow the input surface of the shaping LLM to trusted sources only. [IBAC](https://ibac.dev/ibac-paper.pdf) takes this approach: the intent parser operates exclusively on the user's message and a pre-resolved trusted contact store, explicitly excluding any external data sources the agent has already touched. That does not make the parser deterministic, but it removes the adversarial content path from the shaping step. Parser errors can then over-scope or under-scope, but they cannot be driven by injected content encountered during execution. ## The Context Integrity Problem Even with a perfectly shaped Mission Authority Model, an agent operating in an adversarial environment can be redirected: not by exceeding its authority, but by using its legitimate authority in service of someone else's intent. Prompt injection is the concrete case. The agent is processing a document, an email, or an API response. That content contains adversarial instructions designed to redirect behavior. The enforcement point sees calls that fall within the shaped authority envelope. Nothing is flagged. The user's approved intent has been subverted without a single authorization failure. This is not a problem that shaped authority models solve. It is a problem they cannot observe. Several partial defenses are possible. Isolating the shaping step before the agent reads external content prevents adversarial inputs from influencing the authority model, but only for tasks whose execution path is knowable upfront. Intent anchoring cryptographically binds the approved purpose to the authority artifact and creates a reference point for post-hoc analysis. It does not prevent context taint inside that envelope. Call provenance logging helps reconstruct what happened after the fact. Human confirmation gates on irreversible actions limit the damage an injected instruction can accomplish even when it successfully redirects the agent. But these are not enough on their own. Prompt injection is where containment has to carry more weight than Mission shaping. There is no semantic layer that can observe what happens inside the agent's context window. Context integrity failures compound the runtime alignment problem. A semantically intact Mission Authority Model offers no signal that the agent has been redirected. Every call looks authorized, every action is within bounds, and the alignment signal remains flat. The only layer that can interrupt is containment: mediated tool calls that block categories of action regardless of the instruction that triggered them, and human confirmation gates that fire on irreversible operations before they complete. An agent that cannot exfiltrate data without going through a logged, rate-limited outbound adapter is less useful to an injected instruction even if the instruction successfully redirected the agent's behavior. Consider a less structured case than the CFO workflow: an agent asked to research vendors, summarize options, and begin outreach where appropriate. That task crosses external content, third-party tools, evolving selection criteria, and ambiguous action boundaries. A Mission shaped for that task can still provide a governance record and some outer bounds. But the real safety properties are more likely to come from mediated outreach, short-lived credentials, sandboxed browsing, and explicit release gates before any external communication is sent. This is the kind of open-world case where containment is not a complement to Mission shaping so much as the more reliable layer. # Staged Mission Shaping Isolating the shaping step is the right principle, but it cannot be applied as a single upfront step for most real enterprise tasks. ```text +------------------+ | Human intent | +------------------+ | v +------------------+ | Mission Proposal | +------------------+ | v +------------------+ | Approved Mission | +------------------+ | v +------------------+ | Mission state | | owner | +------------------+ | +--> Stage 1: discovery | | | +--> enforcement | | | +--> discovered facts | | +<------------+ | +--> Stage 2: execution | +--> enforcement | +--> irreversible action | v +------------------+ | Callback / | | re-approval | +------------------+ | v +------------------+ | Mission state | | owner | +------------------+ ``` Many tasks are not fully knowable at the moment of initial approval. An enterprise agent may need to inspect draft spreadsheets, read finance-system metadata, compare version history, or discover which supporting systems are implicated before it can propose the next safe action. If the entire Mission Authority Model must be shaped before any external content is seen, the result will often be too narrow to be useful. If the agent is allowed to inspect arbitrary external content before shaping, the isolation guarantee collapses. That tension is why structured enterprise workflows need a staged model rather than a single compile-once event. In the structured case, staged Mission shaping can include staged compilation. A staged model looks like this: 1. **Shape a narrow discovery envelope.** Enough authority to inspect the immediate problem space: read access to relevant systems, no write operations, no external communications. 2. **Shape a fuller execution envelope from discovered facts.** Still bounded by the original approved purpose, but now informed by what the agent found in Stage 1. 3. **Require explicit expansion, callback approval, or re-confirmation for anything outside the execution envelope.** Novel actions, high-risk operations, and scope expansions all require returning to the Mission state owner. Each stage transition produces a new versioned authority artifact. The Mission state owner, the authoritative lifecycle service for Mission state, is the only party that can issue a new version. In some deployments that is an AS-resident Mission service. In others it is a separate authority service. The architectural requirement is not placement. It is that one system remains authoritative for Mission versions, stage transitions, and lifecycle state. That centralization makes the Mission state owner both the governance anchor and a single point of failure. The Mission state owner is the authoritative lifecycle system for Mission state: the component that owns Mission versions, stage transitions, runtime budget state, and suspension or termination decisions. If it is unavailable during an active Mission, stage transitions stall, [trust budget](/notes/mission-shaping-is-not-enough/#runtime-alignment-trust-scores-and-budgets) exhaustion cannot be acted on, and governed resumption cannot proceed. Availability and resilience requirements for this component are not an afterthought. The staged model also has to handle re-planning when discovery changes the task materially, downgrade paths when later facts narrow rather than expand the task, and attenuation as well as expansion. This clarifies where Mission shaping is strongest: structured workflows with clear stages, observable transitions, and legible approval points. In those domains, shaping can take the form of staged compilation. It is conceptual framing, not a full shaping protocol, but it is enough to see where the model holds and where it starts to fray. Recent work on [semantic task-to-scope matching in delegated authorization](https://arxiv.org/abs/2510.26702) can be read as one concrete instance of this structured case: an authorization server semantically constrains scopes to the task at hand rather than trusting the agent's requested scope set. That is Mission shaping in a narrower, more enumerable form. A complementary approach enforces at the tool-invocation boundary rather than at token issuance: [IBAC](https://ibac.dev/ibac-paper.pdf) and [CaMeL](https://arxiv.org/abs/2503.18813) parse intent into structured permission tuples before execution begins and check every tool call against them deterministically. Token issuance enforcement constrains what authority is granted before the agent runs; tool-invocation enforcement constrains what the agent can do with that authority at every step. Both are instances of the structured case. Neither addresses what happens when authority is shaped correctly but the agent operates across multiple organizations, long-running tasks, or delegation hops where the original approval is long behind the execution. In the most repeatable cases within that structured domain, shaping can go one step further and emit a governed task artifact: a reviewed script, workflow, or executable routine tied to a specific Mission template and task class. That does not mean the artifact carries standing elevated privilege. It means future Missions can invoke a versioned, signed, pre-approved behavior instead of re-deriving the same logic from natural language every time. The authority still comes from the current Mission context. Reusing the artifact is safe only if its inputs, side effects, and invocation conditions remain narrowly bounded. Seeing where staged Mission shaping works makes the gap with what most deployments actually do more visible. # What Most Deployments Do Instead Relatively few current deployments perform Mission shaping as a first-class step. In practice, many systems fall into one of five patterns, including some that look like compilation but are not. | Pattern | What it does | Why it falls short | |---|---|---| | Scope enumeration | Pre-enumerates allowed scopes or APIs at authorization time | Works only for closed-world tasks where the full execution path is known in advance | | App-local policy mapping | Maps recognized intents to internal permission bundles | Not portable, usually opaque to users, and breaks at organizational boundaries | | LLM-generated structured request | Uses an LLM to draft authority inputs | Useful as a proposal step, but probabilistic, non-deterministic, and vulnerable to tainted inputs | | Broad credential plus prompt discipline | Gives the agent wide authority and relies on the prompt to constrain it | Self-governance, not governance; the agent's own judgment becomes the enforcement boundary | | Policy languages (XACML, OPA, Cedar) | Express access control policy in a formal language | Designed for enumerable resources and actions; adapting them to open-world intent requires exactly the semantic work that makes Mission shaping hard | The most common real-world deployments land in the third or fourth pattern. The third pattern has a more disciplined form worth noting separately: systems like [IBAC](https://ibac.dev/ibac-paper.pdf) and [ASTRA](https://arxiv.org/abs/2510.26702) use an LLM to extract intent but enforce the result deterministically, either at the tool boundary or at token issuance. They reduce the taint vulnerability. They do not address whether the extracted intent correctly represents what the user approved โ€” that is the shaping problem this article is about. They are structured enforcement architectures that still depend on an upstream intent-extraction step, not substitutes for solving the shaping problem itself. The majority let the model infer its own boundaries or give the runtime broad authority and rely on local discipline not to misuse it. When the system never explicitly converts approved intent into a bounded authority artifact, the agent's own judgment becomes the effective policy engine. That is not a governance model. It is the absence of one. In effect, the agent becomes the place where requested purpose, system design, business role, and organizational policy are reconciled. That reconciliation should be a governance function, not a runtime improvisation. None of these patterns include containment as an intentional layer either. Containment is usually present as an accident of deployment (the agent happens to be running in a restricted environment) rather than as a first-class design decision. The concrete example that follows shows the staged model working. The failure modes that arise even within it are the subject of [Part 2](/notes/mission-shaping-is-not-enough/). In deployments running these patterns, they arrive faster and without a governance boundary to limit the damage. # A Concrete Example The following example assumes a single organization, known systems, and a structured approval path: the conditions under which staged Mission shaping is most tractable. The interoperability complications that arise at organizational boundaries do not apply here. The CFO says: > Assemble the board packet, reconcile the final numbers, and call me back before releasing anything externally. That is not yet authority. It is intent. It contains at least four different governance questions: - what systems the agent may inspect - what changes, if any, it may make while reconciling numbers - what must wait for callback approval - what counts as "releasing anything externally" A plausible Stage 1 Mission Authority Model might look like: ```json { "mission_version": 1, "allowed_resources": [ { "type": "finance.report", "selector": "period == 2026-Q1" }, { "type": "finance.forecast_version", "selector": "period == 2026-Q1" }, { "type": "board.material", "selector": "classification in ['draft', 'internal']" } ], "allowed_operations": [ "finance.read", "finance.compare", "board.read_internal" ], "constraints": [ { "type": "callback_required_before_release", "value": true }, { "type": "mission_stage", "value": "discovery" } ], "forbidden_operations": [ "board.publish_external", "notification.send_external", "finance.approve_final" ] } ``` If discovery finds only expected variance, the Mission state owner issues version 2. The delta is deliberate. `mission_stage` advances from `discovery` to `execution`, `board.packet_draft` is added as an allowed resource, and write operations (`board.write_internal_draft`, `board.assemble_packet`) are unlocked. The version number increments so enforcement points holding a version 1 token reject it as stale. The CFO's callback requirement remains in force. `board.publish_external` stays forbidden until the CFO confirms. When the callback succeeds, the Mission state owner issues version 3 with external publication unlocked. That is an approval event, not a local agent decision. This is the domain where Mission shaping is tractable: one organizational trust boundary, known systems, a structured approval path, and a control plane that can tolerate transition friction. Even here, the hidden complexity is real. Selector correctness, stage propagation to distributed enforcement points, token freshness, and sequencing for partially-completed write operations all have to be solved. One design decision every implementation will face is whether the token carries the Mission Authority Model inline or carries only a `mission_ref` that enforcement points resolve at call time. Inline tokens enable offline enforcement and reduce latency, but they become stale immediately when the Mission state owner issues a new version. Reference-based tokens stay current but create an availability dependency on the Mission state owner at every enforcement point. Neither choice is obviously correct. The right answer depends on revocation latency requirements and the acceptable blast radius if the Mission state owner is temporarily unavailable. Enforcement points resolving a reference token are performing a form of token introspection ([RFC 7662](https://datatracker.ietf.org/doc/html/rfc7662)) against the Mission state owner. The Mission Proposal can also be submitted to the authorization server with integrity guarantees using Pushed Authorization Requests ([RFC 9126](https://datatracker.ietf.org/doc/html/rfc9126)) before the interactive approval flow begins. That tractability does not generalize to open-world environments. Part 1 stops here because this is the strongest case for Mission shaping: one enterprise, known systems, legible stages, and a control plane that can absorb governance friction. The harder question starts after that. A well-shaped Mission can still fail under quiet scope expansion, delegation, headless execution, stale state, and open-world runtime redirection. That is where containment, runtime alignment, and survivable incorrectness become the more important story. [Part 2: Mission Shaping Is Not Enough](/notes/mission-shaping-is-not-enough/) picks up from there. --- # Why Mission-Bound OAuth Might Be the Wrong Answer Canonical URL: https://notes.karlmcguinness.com/notes/why-mission-bound-oauth-might-be-the-wrong-answer/ Markdown URL: https://notes.karlmcguinness.com/notes/why-mission-bound-oauth-might-be-the-wrong-answer.md The previous three posts in this series made the strongest case for Mission-Bound OAuth: - [Part 1](/notes/mission-bound-oauth-architecture/) argued that a durable Mission object is better than token-only continuity for delegated agent authority - [Part 2](/notes/client-context-and-id-jag-for-mission-bound-oauth/) showed how the authentication layer bootstraps a Mission cleanly and how ID-JAG projects it across same-IdP trust domains - [Part 3](/notes/mapping-mission-architecture-to-aauth/) argued that even AAuth, a cleaner-sheet agent protocol, still appears to need a Mission-like governance layer That is the positive case. This post is the negative one. If I were trying to tear the idea down rather than defend it, I would say this: > Mission-Bound OAuth may be a clever way to improve OAuth-heavy enterprise IAM, but it may also be the wrong home for the problem, the wrong abstraction boundary for agent governance, and the wrong long-term substrate for open-world systems. That critique is worth stating directly, because the architecture is only useful if it survives serious skepticism. The pessimistic argument has five main parts: 1. Mission-Bound OAuth asks the Authorization Server to do too much. 2. It mixes governance state with protocol transport concerns. 3. It depends on an authority-compilation step that is much harder than the OAuth parts. 4. It may still underfit real agent execution, which is messier than the architecture assumes. 5. It may be too broad to standardize well at the semantic layer that actually matters. If those objections hold, then Mission-Bound OAuth is not the right answer to the full problem. At best, it is a transitional answer for organizations that already live inside OAuth. # The Authorization Server Becomes Too Important The architecture looks disciplined because everything routes through the Authorization Server (AS): - Mission creation - approval and attenuation - lifecycle state - delegation depth - verified actor binding - token issuance and exchange - business-event termination - introspection - distributed authority-model retrieval That is elegant on paper. It is also a warning sign. The AS stops being only a credential issuer and becomes all of the following at once: - a durable authority ledger - a lifecycle state machine - a delegation graph authority - an approval evidence store - a policy compilation checkpoint - an event-driven execution governor That concentration creates three distinct problems. ## It creates operational bottlenecks Every serious control point now depends on AS correctness and AS availability. If the AS or the systems it depends on are slow, mission execution slows. If they fail closed, execution stalls. If they fail open, the governance story collapses. This is not incidental. It is a direct consequence of choosing OAuth as the home for Mission governance. A typical enterprise OAuth deployment is already a latency-sensitive component in every user-facing flow. Mission-Bound OAuth adds Mission state lookups, lifecycle checks, compiled authority evaluation, and introspection calls on top of that. Each additional dependency is another failure mode. The staged adoption path in Part 1 acknowledges that the AS may become a bottleneck and calls for a resilience model. But "we need a resilience model" deferred is not the same as "we have a resilience model." For a component that is now the authority source for whether delegated software should continue operating at all, the resilience requirements are much higher than for a standard token service. ## It creates organizational bottlenecks In most enterprises, the team that runs the IdP or Authorization Server is not the team that owns workflow orchestration, business events, agent runtime safety, or domain-specific approval systems. Mission-Bound OAuth assumes those worlds can be joined behind one control plane: the IAM team now also owns Mission lifecycle, approval policies, authority compilation, and business-event integration. Sometimes that is realistic. Often it is not. The IAM team has no operational visibility into the business processes that should drive Mission termination, and the workflow team has no way to extend AS policy to reflect domain-specific authority rules. The result is either a very thin AS-side Mission that only stores lifecycle state and delegates all real governance to downstream systems, or an AS that accumulates domain knowledge it is not structurally suited to own. Neither is the architecture the document describes. ## It creates disproportionate blast radius If the Mission store or the AS is compromised, the attacker does not just gain token issuance influence. They gain the authority layer that decides whether delegated software should still be operating at all. That is a qualitatively different prize than a normal token server. A compromised standard AS lets an attacker issue new tokens with elevated scope. A compromised Mission-bearing AS lets an attacker also rewrite the governance record that downstream systems use to determine whether existing execution should continue. They can activate suspended Missions, prevent revocation from propagating, and silently expand authority envelopes. The delta between those two threat surfaces is not marginal. Mission-Bound OAuth's design compounds this by making the AS the authoritative source for the compiled Mission Authority Model. If that model is stored at the AS and the AS is compromised, an attacker does not just steal tokens. They steal the compiled representation of what each agent is permitted to do, and they can modify it without triggering token rotation. # Governance May Not Belong Inside OAuth The deepest critique is not that the architecture is too complicated. It is that it may be putting the durable authority object in the wrong place. OAuth is fundamentally good at: - issuing tokens - narrowing tokens to audiences - deriving tokens across exchanges - binding tokens to clients and keys Mission governance is about something else: - approval - durable authority state - lifecycle transitions - business-event termination - delegation policy - audit evidence - cross-system authority continuity Those are governance concerns first and OAuth concerns second. Mission-Bound OAuth tries to connect those two layers by making the AS authoritative for the Mission itself. That is coherent, but it is not obviously the best separation of concerns. It may be cleaner to let OAuth consume Mission state rather than own it. There is a simple test for whether an object belongs in a protocol or belongs in a layer that the protocol consumes: > if the architecture still makes sense when the protocol is removed, then the protocol may not be the right home for the primary object. The Mission passes this test. A Mission-like durable authority object makes sense whether the downstream execution layer is OAuth, AAuth, a job scheduler, a workflow engine, or a tool broker. The governance concern exists independently of the transport. That is a strong signal that Mission governance belongs in a separate authority layer and OAuth is one consumer of that layer, not its home. GNAP (Grant Negotiation and Authorization Protocol) is at least suggestive here. One of the recurring adoption questions around GNAP has been whether richer protocol capability and richer governance capability are being introduced together in a way that raises the adoption bar. Mission-Bound OAuth may be taking on a similar risk by coupling the transport improvement and the governance object too tightly. Mission-Bound OAuth makes a similar choice. It is a real improvement in what the AS governs. It may not be the right place to put the object that drives that governance. # The Hard Part Is Not OAuth. It Is Compilation The architecture is at its strongest when it says a Mission is the compilation boundary between ambiguous intent and enforceable authority. That is also where it is weakest. Part 1 describes the compilation step as follows: ```text intent -> Mission Proposal -> Approved Mission -> Mission Authority Model ``` That stack is the right conceptual shape. The hard problem is the first arrow: turning open-ended human intent into a bounded, machine-evaluable Mission Proposal without over-delegating or causing constant re-approval failures. The compilation problem has several hard sub-problems that Mission-Bound OAuth does not directly address. **Semantic ambiguity.** "Schedule a meeting with the engineering team" could mean: read all engineering team calendars, write a calendar event, send email invitations, record the meeting in a CRM, look up attendees' availability across a directory, and propose a room booking. Or it could mean just the calendar write and the email send. The same natural-language intent compiles to very different authority envelopes depending on who is doing the compilation and what they assume. The Mission Authority Model format defines how to express those envelopes. It does not resolve the ambiguity in choosing which envelope is correct for a given intent. **Verification.** Even if you compile a Mission Proposal from a user's stated intent, how do you verify that the compiled result actually matches what the user intended? The approval step is the intended answer: the user sees the compiled authority and approves it. But the gap between what a non-expert user reads in an approval screen and what the machine-evaluable authority model actually encodes can be large. Approval UX that accurately represents a complex compiled authority model is an unsolved design problem, not a layout problem. **Trust in the compilation agent.** If an LLM interprets the user's prompt and proposes the Mission, the compiled authority model is a probabilistic artifact. The same prompt submitted twice may produce different proposals. A prompt injected with adversarial content in a retrieved document may produce a silently expanded proposal. The Mission Authority Model format gives you a way to inspect the result. It does not give you a way to attest that the LLM's interpretation was faithful to the user's intent and free of injection. That attestation problem is pre-OAuth and does not become easier because the result ends up in a well-structured authority model. **Interoperability collapse at the hardest layer.** Part 1 already acknowledges that compilation may become proprietary, and that if every implementation compiles authority models differently, interoperability may exist only at the token-envelope layer. That is the realistic outcome. The purpose taxonomy, the operation groups, the resource selectors, the relationship predicates: all of these require shared semantics to be interoperable. Shared semantics require coordination. That coordination is harder than defining the schema that carries the semantics. The practical result is that Mission-Bound OAuth may be disproportionately elaborate around the easier half of the problem, the OAuth protocol mechanics, while still being under-specified around the hardest half: the semantic agreement that makes compiled authority models meaningful across system boundaries. # The Architecture May Still Underfit Real Agent Execution Mission-Bound OAuth is built around checkpoints: - approval - issuance - exchange - introspection - lifecycle transitions Real agent systems do not only act at those checkpoints. They: - pause and resume unpredictably, often across different runtime processes - switch runtimes when a sub-agent is spun up or a tool call delegates further - re-plan after partial failure, discovering that the initial plan did not account for what they found - discover new tools at runtime through MCP or equivalent capability discovery - accumulate new facts that change what the next step should be - branch into multiple parallel tasks that may have different authority requirements - call systems that are not inside the OAuth fabric at all The MCP tool discovery case is a specific and important example. An agent may be approved for a Mission covering calendar, email, and CRM. During execution, it discovers through MCP that a scheduling assistant tool is available that also touches document storage. The agent never planned to touch document storage. The Mission never anticipated it. But the agent's natural execution path leads there. Mission-Bound OAuth's answer is `mission_authority_exceeded`: the agent gets a structured error indicating that document storage is outside the compiled authority envelope, and it must either stop that path or trigger a Mission expansion proposal. That is the right governance answer. It is also a significant friction point in agent execution that may, in practice, cause agents to request broader initial authority envelopes, defeating the bounded authority goal. The re-planning case is equally challenging. An agent plan that looked like three steps may turn into seven steps because the first three uncovered new information. The Mission approved the three-step view. The seven-step execution may be well within the spirit of the original approval but exceed the compiled authority in specific ways. The architecture's answer is expansion proposals. But expansion proposals require human review cycles, and an agent that hits expansion boundaries mid-execution must either stall, abort, or work around the limitation. The harder challenge is the model-tool boundary. Mission-Bound OAuth governs which API calls an agent is permitted to make. It does not govern what the model does with the response. An agent can read a file it is authorized to read and then include the contents in a message sent to a recipient outside the Mission's authority envelope. The OAuth layer never sees that second action as a distinct authorization event. Mission governance is strong at the resource-access boundary and blind to what happens inside the model's reasoning process. This creates the illusion of governance: > the system feels governed because the token path is governed, while the runtime still has many ways to drift, cache, fork, or route around the intended control points. The architecture acknowledges some of this under practical limits, but the problem is structural, not just a matter of deployment discipline. # The Model May Be Too Broad To Standardize Well Mission-Bound OAuth needs a surprisingly large meta-model: - purpose classes - templates - authority models - resource selectors - relationship predicates - operation groups - lifecycle states - approval evidence - delegation chains - projection policies - event semantics Each piece is individually reasonable. Together they are a substantial standardization surface. XACML is the historical cautionary example. XACML was technically correct. It modeled the right things: attributes, policies, rules, combining algorithms, obligations. It was too complex for most enterprises to author and maintain in practice. Adoption was thin outside specific regulated verticals. The fundamental problem was not that XACML was wrong but that the surface it standardized was too large to be adopted incrementally. Mission-Bound OAuth faces a version of the same problem. The likely failure mode is: - the protocol pieces get standardized at IETF: `mission_ref` as a token claim, token exchange extensions, lifecycle error codes, introspection fields - the semantic pieces remain deployment-specific: purpose taxonomy, compiled authority format, relationship predicates, business-event termination conditions - every implementation uses different authority compilation logic - interoperability exists at the token-envelope layer, not at the authority layer the architecture actually cares about If that happens, Mission-Bound OAuth succeeds procedurally and fails substantively. Operators can exchange `mission_ref`-bearing tokens between any two implementations. But two implementations in the same enterprise still cannot share a Mission, because their compiled authority models are incompatible. The most important interoperability, the kind that makes a Mission's authority meaningful across system boundaries, never arrives. The staged adoption path helps with this by starting with AS-side lifecycle and deferring semantic richness. But the semantic richness is the point. A `mission_ref` that only carries lifecycle state is useful. It is not the Mission Authority Model the document describes. # A Stronger Critique There is an even harsher version of the argument. Open-world agents are not primarily a delegated authorization problem. They are a runtime control problem. The question is not only "is the agent authorized to take this action?" The question is "is the agent behaving consistently with what was intended, and how would we know if it stopped?" Mission-Bound OAuth improves the first question. It does not address the second. Authorization systems govern boundaries. They answer yes or no at defined checkpoints. Runtime control governs behavior between those checkpoints: whether the agent is reasoning correctly, whether it has been manipulated by content in its context window, whether it is producing outputs consistent with the user's intent, and whether human oversight is being exercised at the right frequency. Prompt injection is a concrete example. An agent executing a Mission can be redirected by adversarial content in a tool response. A malicious calendar entry might contain instructions that cause the agent to take actions outside its intended path. The agent's token requests remain within the Mission's authority envelope, because the agent is still calling the APIs it is authorized to call. The governance layer never sees the manipulation. The audit trail shows a sequence of authorized actions that, taken together, represent behavior nobody intended to authorize. Mission-Bound OAuth's threat model includes actor substitution, confused deputy, and scope creep. It does not have a good answer for adversarial content injection because that threat crosses the model-tool boundary in a way that authorization infrastructure is not designed to observe. The stronger critique is not that Mission-Bound OAuth is wrong. It is that it may be misframed. If the real problem is runtime control of autonomous systems, then improving OAuth-level credential governance is necessary but far from sufficient. The right starting point is not: > how do we make OAuth carry longer-lived governed authority? It is: > what authority service governs agent execution, and how do existing protocols consume it? Those are different architecture questions. The second one does not have OAuth at its center. # A Better Answer: Make Mission a Separate Authority Service The most plausible better answer is not "throw away Mission." It is "move Mission out of OAuth." In that sense this post is also a return to the original Power of Attorney intuition. The earlier series treated the state owner more like a mandate or authority service that sat above IAM, policy, and orchestration rather than inside one protocol component. Mission-Bound OAuth narrowed that thesis into an AS-centered protocol architecture. The MAS alternative reopens the broader control-plane version of the idea. The cleaner architecture looks like this: - a dedicated **Mission Authority Service** (MAS) owns Mission state - the MAS handles approval, lifecycle, delegation policy, compiled authority, approval evidence, and business-event termination - OAuth Authorization Servers call the MAS at issuance and exchange time to check Mission state and authority bounds - AAuth authorization servers do the same, because the MAS does not care what protocol is presenting the request - gateways, schedulers, orchestrators, and tool brokers can query the MAS directly for Mission state, without needing an OAuth token in the path - OAuth becomes one projection and enforcement mechanism, not the canonical home of the authority object That produces a cleaner split of responsibilities: | Layer | Responsibility | |---|---| | Mission Authority Service | approval, durable authority state, lifecycle, delegation policy, compiled authority model, evidence, event-driven termination | | OAuth AS | issue and exchange tokens consistent with Mission state from MAS | | AAuth AS | issue AAuth auth tokens consistent with Mission state from MAS | | Runtime / Orchestrator | execute tasks, request new authority from MAS, handle pauses and retries | | Gateways / PDPs / RSes | enforce resource-specific decisions using Mission-derived context from MAS | This is not a radical departure from the Mission-Bound OAuth architecture. The Mission object, the authority model, the lifecycle states, the approval flow, and the audit trail are all the same. The main change is where they live and which component is authoritative for them. That shift does not make the hard problems disappear. A MAS still has to solve authority compilation, event integrity, actor continuity, lifecycle coupling, and operational resilience. The claim is narrower: if those hard problems must exist somewhere, they may belong in a dedicated governance service rather than inside the OAuth AS. **Cleaner separation of concerns.** Mission governance no longer has to be smuggled into OAuth as if it were a token problem. The MAS can be owned by the team that understands workflow and business events. The AS remains the credential issuer it was designed to be. The organizational ownership story becomes much more natural. **Broader applicability.** Not every enforcement path in agent systems is an OAuth path. Job schedulers, internal queues, workflow engines, tool brokers, and MCP servers may need Mission state even when no OAuth access token is in the path. If Mission state lives in the AS, those systems either become second-class consumers or start depending on IAM endpoints that were not built for them. If Mission state lives in a dedicated MAS, they can consume the same authority record through a purpose-built API. **Protocol portability.** If OAuth remains the dominant enterprise deployment substrate, the MAS becomes the AS's upstream authority source. If AAuth or something else becomes better suited later, the MAS survives and the transport layer changes underneath it. Part 3 ended with "Mission governance on AAuth" as the cleaner long-term architecture. A Mission Authority Service is what makes that transition possible without rebuilding the governance layer each time. The practical integration pattern at Stage 1 would look like this: the AS calls `GET /missions/{mission_ref}` on the MAS at exchange time, the MAS returns current lifecycle state and authority bounds, the AS enforces them in the issued token. That introduces real costs: - a new network dependency on the MAS for issuance and exchange decisions - new consistency requirements between AS caches and MAS state - a new governance service that now needs the same operational hardening the AS would otherwise need But those costs buy a cleaner separation of concerns. The critique is not that MAS is easy. It is that its difficulty is more honest: it puts the governance complexity in the layer that actually owns governance rather than embedding it inside the credential issuer. That is the deeper attraction of MAS. It is not only "Mission state moved out of OAuth." It is governance restored as a layer above IAM, policy, and orchestration, with each of those systems consuming Mission state rather than one of them trying to become the whole control plane. # An Even More Conservative Answer There is also a safer answer than either Mission-Bound OAuth or a Mission Authority Service, and it deserves honest consideration. It is less elegant and less autonomous: - do not let agents hold much durable delegated authority at all - keep approvals narrow and frequent - issue per-step credentials - require renewed justification often - treat long-running missions as orchestrated job control, not as persistent delegated continuity This is the principle of least delegation taken seriously: the right amount of authority is the minimum needed for the next specific action, not the maximum that might be needed across the whole intent. That model is worse for user experience and agent autonomy. An agent that needs approval for each step is not usefully autonomous. It is also worse for agents that operate in low-latency workflows where human approval introduces unacceptable delay. And it is worse for headless or service-to-service workflows where a user is not in the loop at all. But it may be better for safety in several important cases. In regulated environments, the compliance risk from a single governance failure may outweigh the UX cost of frequent re-approval. Finance, healthcare, and government deployments where a single unauthorized action triggers audit findings or regulatory penalties may reasonably decide that per-step credentials are worth the friction. The architecture should say so explicitly rather than treating narrow, frequent approval as a degraded mode. In high-stakes action domains, irreversible actions, large financial transactions, external communications, code deployments, database modifications, the governance value of a brief approval moment before each action may be much higher than the value of seamless autonomous execution. Governance tradeoffs are not always won by the smoother user experience. For organizations that are still developing their understanding of how their agents actually behave in production, narrow credentials provide a natural forcing function. You cannot have a runaway agent that accumulates unauthorized capabilities if each capability required its own issuance event. That property is valuable during the early deployment period even if it becomes unnecessary later. The honest conclusion is that Mission-Bound OAuth and the Mission Authority Service architecture described above are both designed around the goal of making autonomous agents work well under governance. The conservative answer is designed around the goal of not having that problem in the first place. Depending on the deployment context, that may be the right engineering decision. # So Is Mission-Bound OAuth a Bad Idea? Not necessarily. The honest conclusion is narrower and less flattering than the architecture post itself. Mission-Bound OAuth may be the wrong answer if the goal is a clean-sheet architecture for agent governance. It may still be a good answer if the goal is to improve governance in OAuth-heavy enterprise infrastructure without replacing the whole stack. That is a meaningful distinction and it matters for how to read the series. Mission-Bound OAuth is strongest as: - a pragmatic retrofit for OAuth-centric environments where replacing the AS is not realistic - an incremental deployment model where Stage 1 lifecycle and delegation enforcement delivers real value before the full architecture is in place - an IAM-native improvement to token exchange, lifecycle, and delegated authority continuity that fits existing Okta, Auth0, or Azure AD deployments with extension It is weakest as: - a universal architecture for open-world agents operating across heterogeneous systems - the natural long-term home of the Mission concept, since Mission governance makes sense independent of OAuth - the only layer at which runtime governance should live, since authorization is necessary but not sufficient for behavioral control The staged adoption path matters here. A deployment that starts with Stage 1, AS-side Mission lifecycle with a projected `mission_ref` claim, gets the core lifecycle and revocation property with minimal architectural disruption. That is a real improvement over token-only OAuth even if stages 2 and 3 never arrive. But it is also the strongest evidence that the full architecture may be doing too much. If the most adoptable and defensible part of the design is the smallest AS-side lifecycle layer, that may be a sign that the rest belongs elsewhere. The answer to that question depends on the deployment. For teams running agent workflows today with no Mission-level lifecycle control, Stage 1 is a clear improvement. For teams evaluating whether to build a full governance infrastructure from scratch, the Mission Authority Service alternative may be worth starting with. # Conclusion The series has made one consistent claim across all four posts: agent authority needs a durable, governed object, not just a chain of well-formed tokens. That claim still holds. The critique in this post is not that the claim is wrong. It is that Mission-Bound OAuth may be a reasonable but suboptimal way to realize it. The most defensible framing for where this lands is: > Mission is the right object. Mission-Bound OAuth may not be the right home. That leaves three things true at once: - the Mission model is directionally right - extending OAuth may be the most practical near-term path for OAuth-heavy deployments - a separate Mission Authority Service, and eventually Mission governance on AAuth or a successor, may be the better end state The series ends here. The argument is not that Mission-Bound OAuth solves agent authorization. The argument is that it identifies the right object and may still put it in the wrong place. The practical test is simpler: is a deployment with Mission-level lifecycle, authority bounds, and delegation control meaningfully better than a deployment without it? For the problems agent systems actually face today, the answer is still often yes. That does not make Mission-Bound OAuth the best answer. It makes it a plausible transitional one. If a deployment can start from a cleaner Mission Authority Service architecture instead, that may be the better bet. --- # Mission Architecture on AAuth Canonical URL: https://notes.karlmcguinness.com/notes/mission-architecture-on-aauth/ Markdown URL: https://notes.karlmcguinness.com/notes/mission-architecture-on-aauth.md This is a follow-up to [Mission-Bound OAuth](/notes/mission-bound-oauth-architecture/). That RFC made one main claim: > agent systems need a durable, governed authority object that survives across token lifetimes, approval delays, delegation hops, and business-event termination. The question here is narrower: If Mission-Bound OAuth is the incremental path for existing OAuth deployments, is [AAuth](https://github.com/dickhardt/draft-hardt-aauth) the clean-sheet path for the same underlying architecture? AAuth (draft-hardt-aauth) is Dick Hardt's proposed agent-native authorization protocol: conversational, signed-request-first, and designed to depart from OAuth's redirect model rather than extend it. Both Mission-Bound OAuth and AAuth are early-stage proposals, so this comparison is necessarily tentative. Either may change materially before any standardization. My current answer is: probably yes, but only if AAuth defines a Mission-like governance object rather than treating purpose and chaining alone as sufficient. If you are skimming, the core claim of this note is simple: - AAuth looks like a better protocol substrate than OAuth for agent authorization. - It still does not obviously remove the need for a durable Mission governance object. - The most plausible long-term comparison is Mission governance on OAuth versus Mission governance on AAuth. At a glance: | Question | Mission-Bound OAuth | AAuth | Remaining Mission profile work | |---|---|---|---| | Approval and clarification | Added through companion APIs and profiles | Native deferred and conversational flow | Approval evidence retention and tamper-evident audit artifact | | Agent identity and proof-of-possession | Added through DPoP, mTLS, `act`, and exchange rules | More native to the protocol | Headless and service-to-service agent identity model | | Chained downstream authorization | Token exchange plus projected Mission context | Native chaining via `upstream_token` | Authority ceiling and bounded expansion rules | | Authentication-layer bootstrap | Client Context companion profile | Largely native to the protocol's signed and deferred interaction model | Cross-domain reduced projection | | Durable lifecycle-governed authority object | Explicitly modeled | Not clearly first-class yet | Mission record, lifecycle states, and independent revocation | | Bounded authority envelope for open-world agents | Explicitly modeled | Not clearly first-class yet | Machine-evaluable Mission Authority Model | | Verified actor continuity across derivation | Now defined explicitly in Mission-Bound OAuth | Not clearly first-class yet | Binding anchor, key continuity across `upstream_token` hops, projection degradation model | # What AAuth Already Gives You One reason AAuth is interesting is that it already has several properties Mission-Bound OAuth has to build indirectly. From the current draft, AAuth already gives you: - signed requests using HTTP Message Signatures - explicit agent identity alongside user identity - deferred authorization with `202 Accepted` - pending-state polling - user clarification during authorization - direct approval flows - chained downstream authorization via `upstream_token` - a first-class `purpose` field That matters because these are exactly the areas where classic OAuth looks most strained in agent deployments. Relevant sections in the current AAuth draft (links reference a specific draft iteration and may shift as the spec evolves): - [Authorization request flow](https://dickhardt.github.io/draft-hardt-aauth/draft-hardt-aauth.html#section-11.2) - [Deferred responses and pending state](https://dickhardt.github.io/draft-hardt-aauth/draft-hardt-aauth.html#section-10) - [User interaction](https://dickhardt.github.io/draft-hardt-aauth/draft-hardt-aauth.html#section-11.5) - [Direct approval](https://dickhardt.github.io/draft-hardt-aauth/draft-hardt-aauth.html#section-4.5.6) - [Call chaining](https://dickhardt.github.io/draft-hardt-aauth/draft-hardt-aauth.html#section-4.5.8) - [Purpose](https://dickhardt.github.io/draft-hardt-aauth/draft-hardt-aauth.html#section-14) # Why This Comparison Matters Mission-Bound OAuth was never mainly about adding another token claim. Its real claim was that delegated machine authority needs to be represented as a governed object: - proposed - approved or attenuated - stored durably - enforced across derivation steps - revocable independently of token lifetime - terminable when the business reason ends AAuth changes the protocol substrate substantially. It is more conversational, more agent-native, and stronger by default on proof-of-possession and chaining. So the real question is: Does AAuth already solve the governance problem by virtue of having better protocol structure, or does it still need an explicit Mission-like authority layer? # The High-Level Mapping This is the rough mapping I would use today. | Mission Architecture | AAuth Equivalent | Notes | |---|---|---| | Mission Proposal | Signed authorization request to the AAuth authorization server | AAuth already has a stronger request object than OAuth auth requests | | Approval / attenuation | Deferred approval, pending URLs, clarification, direct approval | AAuth already has the right control-flow shape | | Mission subject binding | User interaction plus delegate-user binding | Cleaner than stitching this through OAuth redirects and token exchange | | Mission-bearing runtime artifact | AAuth auth token and chained request context | Better native fit than layering RFC 8693 plus custom rules | | Sender constraining | HTTP Message Signatures plus key binding | Stronger default than bearer-heavy OAuth deployments | | Clarification during approval | Native deferred clarification flow | Much more natural for agent systems | | Mission Authority Model | No exact built-in equivalent yet | This still looks like the main gap | | Lifecycle-governed authority object | Not clearly first-class in the current draft | This is where Mission semantics still appear useful | # Where AAuth Looks Better There are at least five places where AAuth looks cleaner than Mission-Bound OAuth. ## 1. Approval and clarification are native Mission-Bound OAuth has to introduce proposal endpoints, approval endpoints, pending states, and optional clarification flows around an OAuth core that was not designed for conversational authorization. AAuth already has the right shape: - signed request - `202 Accepted` - pending URL - follow-up interaction - direct approval path That is a more natural fit for agent authorization than stretching classic OAuth redirects into a multi-step approval conversation. ## 2. Agent identity is part of the protocol Mission-Bound OAuth has to work hard to distinguish: - subject - client - active actor - delegation chain because OAuth starts from the client model, not the agent model. AAuth is much closer to the reality that software agents are actors in the protocol, not just hidden implementation details behind a client. One deployment caveat: AAuth identifies agents via HTTPS URLs pointing to published metadata at `/.well-known/aauth-agent.json`. That works well for internet-scale agents with public endpoints. It is a meaningful assumption for enterprise environments where internal microservices, batch jobs, and RPA workflows today register as OAuth clients and often have no public-facing HTTPS endpoints. A Mission profile for AAuth would need to address this, either through an enterprise agent registration companion or a fallback identity model for internally-scoped agents. ## 3. Proof-of-possession is the baseline Mission-Bound OAuth has to strongly recommend DPoP or mTLS because durable delegated authority on bearer tokens is too risky. AAuth starts from signed requests. That is a much better default for any protocol that wants to make serious claims about agent governance. ## 4. Chaining is built in Mission-Bound OAuth relies on token exchange, projected Mission references, and careful downstream derivation rules. AAuth already has a better native story for chained authorization through `upstream_token`. One important caveat: Section 4.5.8 of the current draft explicitly flags call chaining as an exploratory feature: "The mechanism described here may change." It is a better starting point than OAuth's approach, but it is not yet a stable protocol surface. ## 5. Authentication-time bootstrap may be less awkward One thing that has become clearer since the original Mission-Bound OAuth writeup is that classic OAuth needs an authentication-layer companion profile to do this cleanly. In the OAuth world, [Client Context and ID-JAG for Mission-Bound OAuth](/notes/client-context-and-id-jag-for-mission-bound-oauth/) had to define how purpose gets carried into the authentication step and how a reduced Mission view gets projected across same-IdP trust domains. AAuth likely reduces the need for a separate Client Context-style bootstrap mechanism because signed requests, deferred approval, clarification, and direct approval are already native parts of the protocol flow. That is a real advantage. But it does not automatically remove the need for the other half of that companion story: a durable Mission record after approval, and a reduced projection model for cases where authority needs to cross domains or be consumed by downstream systems that do not hold the full authoritative state. In compact form, the comparison now looks like this: | Concern | OAuth-side answer today | Likely AAuth-side answer | |---|---|---| | Authentication-time bootstrap | Client Context companion profile | Mostly native to AAuth interaction flow | | Durable authority object | Mission-Bound OAuth Mission record | Still needs an AAuth Mission profile | | Machine-evaluable authority model | Mission Authority Model | Still needs an AAuth Mission profile | | Cross-domain reduced projection | ID-JAG-style companion profile | Still needs an AAuth projection profile, even if not ID-JAG specifically | | Verified actor continuity | Mission-Bound OAuth verified agent binding | Still needs an AAuth Mission profile | # Where The Mission Model Still Adds Something This is the key part. Even if AAuth is the better substrate, I do not think it obviously removes the need for the Mission architecture. ## 1. `purpose` is not the same thing as a Mission AAuth has a `purpose` field, and that is useful. It is also slightly richer than pure display text: AAuth's clarification chat mechanism (Section 11.4) allows users to ask questions about the stated purpose during authorization, so `purpose` is conversationally live during the exchange, not just a consent label. But `purpose` is still a free-form human-readable string. The spec defines no allowed values, no machine-processable semantics, and no policy-enforcement hooks. It is not automatically: - a durable authority object - a versioned authority model - a lifecycle record - an audit artifact - a bounded authority envelope > Mission-Bound OAuth's strongest idea is not "show more purpose text to the user." It is "treat delegated authority itself as a governed object." ## 2. Deferred approval is not the same as lifecycle governance AAuth clearly has a better pending/approval story than OAuth. What is less clear is whether the resulting authorization becomes a durable lifecycle object that can later be: - suspended - resumed - revoked independently of token refresh - terminated by external business events - inspected as its own governance record That is still a separate architectural concern. Notably, the current AAuth draft explicitly puts token revocation out of scope. Section 20.10 states "Token revocation is not defined in this specification." This is not an oversight; it is an explicit deferral. The only termination mechanism is expiry followed by refused renewal, which is reactive rather than proactive. There is also no event notification or business-event hook of any kind. ## 3. Chaining is not the same as a bounded authority envelope AAuth's chaining model gives provenance, but it introduces a specific least-privilege hazard: `upstream_token` is explicitly "not a scope ceiling" per the spec. Downstream authorization servers evaluate their own policy independently and may grant scope broader than what was authorized upstream. Without an explicit Mission-like envelope, nothing in the protocol prevents that expansion. > A chain of AAuth hops can expand effective authority, not just narrow it. That is not a gap in AAuth's design for its stated goals. It is a gap between AAuth's chaining model and what Mission governance requires. The chaining model does not automatically define: - what downstream discovery is inside approved bounds - what requires fresh approval - how jurisdiction, relationship, or business-process constraints are preserved - how open-world exploration stays governable That is exactly the job the Mission Authority Model was designed to do. ## 4. Better actor modeling is not yet the same as verified actor continuity Mission-Bound OAuth now defines `Verified Agent Binding` explicitly: the Mission record is the binding anchor, sender constraining carries key continuity, the AS performs actor verification at exchange time, and cross-domain projection is treated as a degraded case unless live state is shared. AAuth is directionally better here than OAuth because agent identity and proof-of-possession are closer to the protocol core. But that is still not the same thing as a defined continuity model that answers: - what is the binding anchor for the approved actor, and how does it survive across AAuth interaction restarts or renewed requests - how key continuity is enforced across `upstream_token` hops, where each AS is re-evaluating independently - what exactly crosses a trust boundary in projected form, and what must remain authoritative at the home AS - where actor continuity degrades to projection-only evidence, and what that means for enforcement at downstream resource servers Signed requests make actor identity visible at each hop. They do not automatically define whether the actor presented at hop N is still the same actor the Mission originally approved, or whether a delegation event has occurred that requires fresh Mission authorization. That still looks like Mission-profile work rather than something the current AAuth draft gives you automatically. ## 5. FGA still needs a bounded intermediate artifact One of the more important arguments in [Mission-Bound OAuth](/notes/mission-bound-oauth-architecture/) is that Missions make AuthZEN/FGA-style decisioning practical for agents by narrowing the search space. That argument does not go away if the protocol substrate changes. Even on AAuth, you still seem to need something like: - a Mission Proposal - an Approved Mission - a Mission Authority Model or you still face the same question: how does open-ended intent become a bounded, evaluable authority context that policy engines can use safely? ## 6. Approval evidence and audit trail Mission-Bound OAuth eventually had to make approval evidence a first-class artifact: what was shown, who approved it, and what authority model was actually bound to that approval. AAuth has strong approval mechanics. What is less clear is whether the resulting authorization retains a verifiable approval artifact after the exchange completes. For regulated deployments in finance, healthcare, or government, this is a compliance requirement independent of how good the interaction flow is. A tamper-evident record of what was presented for consent, who approved it, and what authority was bound to that approval is required by regulation regardless of protocol quality. AAuth's conversational approval model is much better than OAuth's redirect, but the retention and verifiability of that evidence needs to be explicit in any Mission profile. ## 7. Headless and service-to-service missions AAuth identifies agents via HTTPS URLs pointing to published metadata. That works well for internet-scale agents with public endpoints. It is a meaningful assumption for enterprise environments where internal microservices, batch jobs, and RPA workflows often have no public-facing HTTPS endpoints. A Mission profile would need to address this for deployments where the executing actor is not a public agent with a well-known URL. The Mission record already separates `mission_subject.sub` and `mission_client.client_id` as the binding anchor. An AAuth Mission profile would need an equivalent internal-agent registration model for actors that cannot serve agent metadata at a well-known HTTPS address. ## 8. Authority compilation boundary One of the stronger arguments in Mission-Bound OAuth is the separation between intent and compiled authority: ```text intent -> Mission Proposal -> Approved Mission -> Mission Authority Model ``` AAuth's `purpose` field carries intent forward, and its approval flow is much richer than OAuth's. But the compiled authority artifact, the machine-evaluable model that gateways and policy engines reason over, does not appear automatically from a better approval flow. That compilation step, from human-meaningful approval to machine-evaluable bounds, still looks like explicit profile work. Without it, every enforcement point has to re-derive what the approval meant from the same free-text inputs, with no guaranteed consistency. ## 9. Cross-domain semantics AAuth is well suited to signed interactions, but that does not automatically answer: - what authority crosses a trust boundary - what should be projected versus re-evaluated - whether the source authority object is preserved or remapped locally The OAuth companion profile now answers this in one concrete deployment shape: keep the Mission authoritative at home, and use a reduced projection when a downstream same-IdP domain only needs a bounded subset. An AAuth-based architecture may not need the same mechanism specifically, but it would still need to answer the same projection question explicitly. # The Cleanest Alternative The cleanest alternative is not: โ€œreplace Mission-Bound OAuth with AAuth and forget the Mission idea.โ€ It is: โ€œuse AAuth as the protocol substrate and express Mission semantics as an AAuth profile.โ€ That profile would likely add: - a durable Mission record at the authorization server - a projected Mission reference in auth artifacts - Mission lifecycle independent of token expiry - authority-envelope checks on downstream grants - business-event termination hooks - Mission-level audit and approval evidence In that design: > AAuth replaces the OAuth transport and token choreography. The Mission remains the governance layer. That may be the cleaner long-term architecture. # Open Questions for AAuth **Does AAuth want a durable authority object at all?** If yes, the Mission architecture maps naturally onto AAuth as a profile. If no, AAuth is solving a different problem: cleaner authorization choreography, not governed delegated authority over time. That is worth knowing explicitly, because it determines whether "Mission governance on AAuth" is a natural extension or an awkward graft. **How does downstream attenuation fit?** Mission-Bound OAuth has an open question around Biscuit-style attenuation and chained restrictions that does not disappear on AAuth. If anything it becomes more pressing, because AAuth is already more comfortable with chained, signed protocol artifacts. The right layering looks similar regardless of substrate: Mission governance decides whether the authority should exist and continue; a downstream attenuation mechanism decides how authority can be further narrowed or chained; the attenuation layer must remain bounded by the Mission. AAuth's native comfort with signed chaining makes it a better place to answer this question. **Is `purpose` meant to become structured?** `purpose` is conversationally live during authorization, which is a real advantage. But it is not machine-processable or policy-bearing in the current draft. Is that the intended long-term design, or should it become a structured, URI-identified authority claim? Section 9.1 of the draft acknowledges the gap and defers to a future version. The answer to this question determines how much of the Mission Authority Model compilation step an AAuth profile would need to define explicitly. **Does `upstream_token` imply a scope ceiling?** The current spec is explicit that it does not: downstream authorization servers evaluate their own policy independently. For Mission governance, that is a significant gap. A Mission profile would need to define whether the Mission envelope overrides this behavior, and if so, how downstream ASes learn the ceiling and how violations are handled. **How should headless missions work?** AAuth's agent identity model assumes a publicly resolvable HTTPS URL. What is the identity and binding model for internal service agents, batch workers, and automation that have no public endpoint? Any enterprise-oriented Mission profile would need to define this, either through a companion registration mechanism or a fallback binding model for non-public agents. **What would the smallest useful Mission profile actually standardize?** Not a full redesign, just the minimum that makes Mission governance on AAuth viable: a durable Mission record, a projected `mission_ref` claim, lifecycle states independent of artifact expiry, and a bounded expansion rule for `upstream_token` chains. That profile boundary matters because it determines what AAuth itself needs to change versus what lives purely in a companion specification. # Defining The AAuth Mission Profile If the right long-term answer is "Mission governance on AAuth," then the useful next step is not another abstract checklist. It is a concrete profile shape. This is the AAuth Mission profile that seems to fall out of the comparison. ## 1. Mission Creation From Approved AAuth Requests An approved AAuth interaction should not terminate at "authorization granted." It should produce a durable Mission record at the authorization server. The profile boundary is: | AAuth interaction layer | Mission-governance result | |---|---| | Signed authorization request | Mission Proposal input | | Deferred approval / clarification / direct approval | Approval and attenuation step | | Successful authorization outcome | Approved Mission creation | | Returned auth artifacts | Projected reference to the durable Mission | The key rule is simple: the live request is not the durable authority object. It is the input from which the durable authority object is created. ## 2. Mission Record And Mission Reference The profile should define two distinct things: - a durable Mission record held by the AAuth authorization server - a projected `mission_ref` carried in auth artifacts and chained requests That gives the AAuth-based design the same separation that Mission-Bound OAuth now uses: - the server governs the authoritative Mission record - protocol artifacts carry a projected reference - downstream systems reason over projected facts, not the full internal record Without that split, AAuth interactions stay cleaner than OAuth, but the architecture still lacks a stable authority object that survives across chained execution. The service boundary can also stay looser than this post has mostly assumed. One plausible long-term architecture is not only "AAuth plus Mission profile" but "AAuth plus separate Mission authority service," where the AAuth authorization server consumes Mission state instead of owning it directly. That is closer to the control-plane model from the original Power of Attorney series and may be the cleaner separation if AAuth matures into the transport layer while Mission governance remains its own system of record. ## 3. Machine-Evaluable Mission Authority Model The profile should define a machine-evaluable Mission Authority Model derived from the approved Mission, not just from the current request state. At a minimum, that model needs to carry: - purpose class - bounded resource selectors or equivalent authority envelope - operation groups or action classes - lifecycle bounds - delegation bounds - approval attenuations And it needs an explicit access path for enforcement points, for example: - Mission introspection - a signed Mission Authority Model artifact - tightly bounded Mission-derived claims in AAuth auth artifacts This is the same separation Part 1 had to make on OAuth: ```text approved request -> Approved Mission -> Mission Authority Model -> projected artifacts for runtime use ``` The protocol substrate may change, but the architecture still needs that artifact stack. ## 4. Lifecycle Independent Of Token Expiry The profile should define Mission lifecycle as separate from the lifetime of any single AAuth artifact. That means the Mission can be: - suspended - resumed - revoked - completed - expired and those states must govern whether new artifacts can be issued or chained, independent of whether a previously issued token or authorization artifact is still structurally valid. This is where AAuth's stronger interaction model stops being enough on its own. Deferred approval is not lifecycle governance. A Mission profile has to add that layer explicitly. ## 5. Approval Evidence As A Retained Artifact The profile should define approval evidence as something the authorization server retains in a tamper-evident form. At minimum, that evidence has to answer: - what the user was shown - what the user approved - what authority model was bound to that approval - what attenuation or clarification happened before approval That is especially important if AAuth's conversational approval flow becomes one of its main differentiators. The richer the interaction, the more important it becomes to retain the evidence of what actually happened. ## 6. Verified Actor Continuity The profile should define actor continuity explicitly, not assume it falls out automatically from signed requests. At minimum, it needs to answer: - what binds the approved actor to the Mission record - how that actor is re-verified at each chained derivation step - when a new actor is treated as a delegation event - what is authoritative in the home domain - what degrades to projection-only evidence across trust boundaries This is where the AAuth profile should parallel the `Verified Agent Binding` work in Mission-Bound OAuth rather than hand-wave past it. ## 7. Cross-Domain Projection Rules The profile should define what crosses a trust boundary and what must stay local. That means distinguishing: - the authoritative Mission record, which stays at home - the projected Mission reference - the reduced set of Mission-derived facts another authorization domain may rely on - the facts that must always be re-evaluated locally An AAuth Mission profile may not need ID-JAG specifically, but it still needs the same architectural answer the OAuth companion profile now gives: reduced projection, not portable authority. ## 8. Bounded Expansion For Open-World Execution The profile should define a bounded expansion model that overrides the current `upstream_token` "not a scope ceiling" behavior. The key question is the same one the OAuth architecture had to answer: > Is this newly discovered downstream action still inside the approved Mission envelope, or does it require fresh approval? If the profile cannot answer that mechanically, then AAuth's cleaner chaining model still leaves the core governance problem unresolved. ## 9. Orchestration-Layer Landing The profile also has to land in the runtime, not just in the authorization server. That means the AAuth-side architecture needs an answer for: - how an orchestrator pauses or terminates execution when Mission state changes - how irreversible steps trigger escalation instead of blind retry - how compensating or unwind behavior is tied to Mission lifecycle rather than left as local runtime convention This is the same lesson as in the OAuth architecture: a governed authority object that never reaches execution control is only partially real. ## A Compact Profile Summary In compact form, the AAuth Mission profile would need to define: | Profile element | Why it exists | |---|---| | Durable Mission record | So authority survives beyond the current AAuth interaction | | `mission_ref` projection | So artifacts can reference Mission state without exposing the full record | | Mission Authority Model | So gateways, PDPs, and RSes have something machine-evaluable | | Lifecycle model | So Mission state can terminate or suspend execution independently of artifact expiry | | Approval evidence artifact | So approval remains auditable and tamper-evident | | Verified actor continuity | So the approved actor and the executing actor stay meaningfully linked | | Cross-domain projection rules | So trust-boundary behavior is explicit | | Bounded expansion rules | So open-world discovery remains governable | That is not a full protocol redesign. It is a governance layer on top of a cleaner substrate. And it still does not eliminate the need for a continuous authority evaluation layer distinct from request authorization. AAuth may be the cleaner transport, but Mission governance still has to answer whether execution should continue as conditions change over time, not merely whether the next signed request is well-formed and in-bounds. # Conclusion The framing that matters is not "Mission-Bound OAuth or AAuth." It is "Mission governance on OAuth" versus "Mission governance on AAuth." That separation is more useful because it keeps the governance model distinct from the transport substrate. AAuth changes the protocol layer substantially, in ways that make it a better substrate for agent authorization. It does not change the underlying requirement: delegated machine authority needs to be represented as a governed object, not just as a better interaction flow. > If Mission-Bound OAuth is the retrofit, AAuth may be the native habitat. --- # Client Context and ID-JAG for Mission-Bound OAuth Canonical URL: https://notes.karlmcguinness.com/notes/client-context-and-id-jag-for-mission-bound-oauth/ Markdown URL: https://notes.karlmcguinness.com/notes/client-context-and-id-jag-for-mission-bound-oauth.md The [Power of Attorney series](https://notes.karlmcguinness.com/series/you-dont-give-agents-credentials-you-grant-them-power-of-attorney/) argued that agent authority needs to be bounded by purpose, scope, conditions, and lifecycle, not inferred from credentials alone. The [Mission-Bound OAuth RFC](/notes/mission-bound-oauth/) made that concrete: the Mission is the durable authority object at the authorization server, tokens and assertions are derived artifacts, and the projected `mission` claim (`id` plus `origin`) ties them together. This post is about a narrower question: what role does the *authentication layer* play? The short answer is that authentication is the one moment in an agent workflow when the user is present: when intent can be confirmed, step-up can happen, and approval evidence can be captured. That makes it the natural bootstrap point for a Mission. [OpenID Connect Client Context](https://github.com/mcguinness/connect-client-context) is the mechanism for doing that cleanly. When Mission approval cannot complete synchronously, the [OpenID Connect Deferred Token Response Flow](https://github.com/gniero/oidc-dtr-resources) (DTR) handles the asynchronous path. When the Mission later needs to cross into another authorization domain inside the same enterprise, [ID-JAG](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/) (Identity Assertion Authorization Grant) is how a reduced Mission projection can travel without dragging the full authority model with it. None of these is an alternative to Mission-Bound OAuth. Together they form an authentication-layer companion profile for it. # The Audience Problem Take a concrete scenario. An agent is asked to schedule a meeting with the engineering team, send the invitations, and record the follow-up in the CRM. Three services. Three authorization servers (ASes). OAuth access tokens are audience-bound by design: the token issued for the calendar API is not valid at the CRM. That is intentional, as audience restriction prevents token replay across services, but it creates a structural problem for governed agent execution. [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange exists for this. Rich Authorization Requests (RAR, [RFC 9396](https://datatracker.ietf.org/doc/html/rfc9396)) can shape what each token contains. The [OAuth Identity Chaining](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-chaining/) draft profiles how identity propagates across AS boundaries. None of these, by themselves, create what a governed agent mission actually needs: a single durable authority object that all three token issuances trace back to, with a unified lifecycle that can be suspended, revoked, or terminated as a unit. > An agent mission that spans three authorization domains needs more than three shaped tokens. It needs one governed authority object behind them. The challenge is not that no cross-domain mechanism exists. The challenge is that each target AS needs bilateral trust with the source AS, must understand the specific semantics being propagated, and must apply them consistently. Inside a single organization's infrastructure, this can work. Across the vendor and SaaS ecosystem an enterprise agent actually operates in, it does not scale reliably. That is exactly the gap Mission-Bound OAuth fills. Once the Mission exists at the AS, token exchange and RAR become derivation mechanisms, ways to mint audience-specific tokens inside the governed envelope. The question this post addresses is earlier in the flow: how does the Mission get started when a user is in the loop? # The Gap Mission-Bound OAuth Leaves Open Mission-Bound OAuth defines what governed authority looks like and how it behaves. What it did not yet define directly was the authentication-layer companion path: how an interactive OpenID Connect event binds a Mission to an actual human who explicitly delegated a specific authority to a specific agent for a specific purpose, with identity verified at a known assurance level. Without an authentication layer, the Mission bootstrap problem has three unsolved parts. **The Mission knows what was approved, but not that the user actually confirmed it.** Mission-Bound OAuth's interactive approval path shows the user a consent display and captures their response. But without an OpenID Connect (OIDC) authentication event, there is no OpenID Provider (OP)-verified identity assertion binding that approval to a specific authenticated subject at a specific assurance level. The Mission records that *someone* approved it. It does not record *who*, with what authentication strength, or what was cryptographically confirmed at the moment of approval. For regulated or high-stakes delegation, that gap matters: the authority chain cannot be traced back to a verified human principal. **Open-world agents cannot have their authority envelope set correctly at Mission creation.** The core thesis of the Power of Attorney series is that agents need bounded, governed authority, not just credentials. For open-world agents that discover resource requirements at runtime, this creates a hard problem without an authentication layer: the Mission envelope has to be set at creation time, before the agent knows what it will encounter. The only options without a user-confirmed bootstrap are to make the envelope as broad as the purpose class allows (defeating the governance goal), or to make it narrow and accept constant re-approval failures (defeating the usability goal). Neither is acceptable as a foundation for agents that are supposed to operate autonomously inside governed bounds. The `params` object in the purpose context helps break this dilemma. The user authenticates at Mission initialization, confirms a purpose, and the agent supplies the specific parameters that bound the task. The AS can use these inputs to compile a Mission Authority Model that is tight enough to be meaningful governance and broad enough to cover the agent's declared intent, without requiring the agent to enumerate every downstream audience in advance. That is the only path to a Mission that governs open-world execution rather than only closed-world workflows. **Cross-domain projection has no trust foundation without a shared identity anchor.** Mission-Bound OAuth describes cross-domain Mission assertions for reaching authorization domains outside the home AS. But every bilateral trust relationship required to make those assertions work has to be established separately. In most enterprise deployments, the Identity Provider (IdP) is already the trust anchor: every Resource AS already trusts it. ID-JAG leverages that existing trust to project a minimal Mission view across same-IdP boundaries without requiring new AS-to-AS federation agreements. Without the authentication layer, you either accept the bilateral establishment cost for each new domain, or the agent's authority simply cannot cross same-IdP boundaries in a governed way. These are not gaps that tighter scope strings or stronger credentials can fill. They are gaps in the *trust foundation* of the Mission. A Mission created by a client asserting a purpose, without a user authentication event, without OP-confirmed identity, and without step-up enforcement, is not Power of Attorney. It is a client claiming authority on behalf of a user who was never in the room. > For Mission governance to be real rather than nominal, the delegation has to trace back to an authenticated human who actually confirmed it. Client Context and ID-JAG are how that traceability is established at the authentication layer. # Authentication Is the Right Bootstrap Moment When a user kicks off an agent task through an interactive authentication event, something important is true that will not be true again until the user reappears: the user can read what they are approving, step-up can be triggered if the risk warrants it, and whatever they confirm becomes a tamper-evident approval record. That moment has always been where identity systems do their most important work. For agent missions, it is also where the Mission can be created or approved, with the user's explicit confirmation of purpose and scope, captured at the one point in the workflow where the human is genuinely present and attentive. [OpenID Connect Client Context](https://github.com/mcguinness/connect-client-context) is structured context attached to an OIDC authentication request. It is not a new credential type and it is not a replacement for OAuth tokens. It is the mechanism for making authentication intent machine-readable and policy-evaluable, so that the OP and its associated AS can act on it. Specifically, the OP can use the applied context to create or approve a Mission at the AS, establishing the governed authority object before any tokens are issued. This matters only for user-delegated scenarios where a human is in the loop. Automated workloads with no human initiator, headless services, and pre-provisioned mission types use client credentials rather than interactive OIDC. Client Context is an extension of interactive OIDC, not a general-purpose bootstrap mechanism for every mission type. That also means Client Context does not replace the broader control plane the older Power of Attorney framing called for. It bootstraps the Mission at the one moment a human is present. It does not answer the later question of whether runtime execution should continue after downstream facts, business events, or orchestration state change. # The Purpose Context For agent missions, the context type that matters most is `purpose`. A purpose context for the scheduling scenario might look like this: ```json { "kind": "https://example.com/purposes/schedule-meeting", "display": { "title": "Schedule Meeting", "description": "Schedule a meeting with the engineering team and record the follow-up" }, "params": { "calendar": "engineering@example.com", "date_range": "2026-04-01/2026-04-08" }, "actor": { "type": "agent", "id": "assistant-agent-v2", "sub": "user-123" }, "constraints": { "expires_at": "2026-04-01T17:00:00Z", "max_duration": 900 } } ``` Each field has a distinct job. `kind` is the stable purpose class the OP uses for policy lookup: it is the join key between the authentication layer and the Mission-creation rules at the AS, stable across deployments and reusable across requests of the same type. `params` are instance-level inputs: the specific calendar, the specific date range. They bound this particular run without carrying authority semantics themselves. `display` is a client-supplied UI hint the OP can present, supplement, or re-render so the user understands the task being approved. `actor` gives the OP advisory context about whether a human, agent, or service initiated the request; unless the client is separately authorized to assert it or the OP verifies it independently, it is not a verified fact. `constraints` bound the authentication event and its immediate outputs. Together that is enough to bootstrap a Mission. It is not enough to replace one: the ID Token is not the authority artifact; it is evidence that authentication and approval happened. The Mission is the authority artifact, and it lives at the AS. The `kind` field is architecturally the most important piece. A Mission profile can use it to map into purpose templates, approval workflows, or Mission-creation rules without forcing the base Client Context spec to define any of those things itself. It is the seam between the authentication layer and the authorization governance layer. # The Handoff The handoff has five steps: the client sends `client_context` during interactive authentication; the OP evaluates it, applying authentication policy, presenting purpose information to the user, and handling step-up if needed; the OP returns the applied `client_context` in the ID Token and retains the approval evidence; the client verifies the returned `client_context` claim rather than trusting what it originally sent; the OP or its associated AS uses that applied context to create or approve a Mission; from that point, Mission-Bound OAuth takes over. The easiest way to think about the data model is: | Form | Where it exists | What it means | |---|---|---| | Requested context | Authorization request | What the client asked the OP to evaluate | | Applied context | ID Token `client_context` claim | What the OP validated and actually used | | Projected context | ID-JAG or other downstream assertion | The reduced Mission-derived view a specific downstream audience needs | What the AS receives from the applied Client Context: the purpose class as a stable policy key, the validated instance parameters, the authenticated subject, any actor information the OP has accepted as verified or retained as advisory context, and the retained display evidence for audit. What the AS creates in response: an Approved Mission with a Mission Authority Model, and a projected `mission` claim that downstream token derivation can reference. The deployment boundary can still vary. In the OAuth-centered model used in this series, the Mission lives at the AS. In a broader control-plane architecture, the same applied context could be handed to a separate authority service that becomes the Mission state owner and the AS becomes one consumer of that state. The authentication-layer handoff is the same either way. > The ID Token carries evidence that authentication and approval happened. The Mission carries the authority. Those are different jobs and they belong in different artifacts. Once the Mission exists, the agent can get a calendar token, an email token, and when the time comes, a CRM token. All three trace back to the same Mission. All three are bounded by the same authority model. All three are under lifecycle that the AS can suspend, revoke, or terminate as a unit. The user approved the purpose once. The system enforces it everywhere. That still leaves one more layer above this post's scope: execution control. Authentication confirms who approved what purpose. It does not by itself ensure that the orchestrator pauses, unwinds, or escalates correctly when the Mission later changes state. That is why this profile is a bootstrap and projection companion, not the whole governance system. # When Handoff Cannot Complete Immediately The handoff description above assumes synchronous OIDC: the user completes interaction, the OP issues an ID Token, Mission creation follows. That assumption holds for purpose types that auto-approve from a policy rule or that the user can confirm interactively in a single session. It breaks for purpose types that require more. High-risk or high-assurance Mission bootstrap may need: - identity verification beyond what can complete in a session, such as document scanning or biometric review that a human operator evaluates - human approval of the Mission Proposal before authority is granted, where that approval follows an out-of-band review process - step-up assurance that depends on an asynchronous channel For these cases, the [OpenID Connect Deferred Token Response Flow](https://github.com/gniero/oidc-dtr-resources) (DTR) provides the right shape. DTR is an emerging OpenID Connect specification that lets a user initiate an authentication flow, leave, and receive the result asynchronously. The user completes their interactive portion: providing identity information, expressing intent, stepping through any immediate prompts the OP requires. The OP responds not with a redirect containing an authorization code, but with a `deferred_code`. The RP exchanges that code for a `deferred_auth_id`, then polls the token endpoint or waits for a ping callback until the authentication decision is made. The `deferred_code code` response type is the most useful form for Mission bootstrap. It lets the OP decide at runtime whether the Mission can be bootstrapped immediately (returning a `code` on the redirect) or requires deferred processing (returning a `deferred_code`). The RP handles both paths from the same initial request. Purpose types that auto-approve compile a Mission immediately; purpose types that require human review enter a pending state. The response type is the OP's signal about which path applied. The mapping between DTR states and Mission states is direct: | DTR state | Mission lifecycle equivalent | |---|---| | `deferred_code` returned on redirect | Mission Proposal submitted; approval pending | | `deferred_auth_id` received from exchange | Mission Proposal accepted for review | | `authorization_pending` at token poll | Mission in pending state | | Successful Token Response with ID Token | Mission approved and activated; Mission creation proceeds | | `access_denied` error | Mission Proposal denied | | `expired_token` error | Mission Proposal expired without decision | The ping callback, sent to the RP's `deferred_client_notification_endpoint` when the authentication decision is made, is the authentication-layer equivalent of Mission lifecycle notification. For deployments that already use SSF/CAEP for Mission lifecycle events, the architectural role is the same: the OP signals completion asynchronously rather than making the RP poll indefinitely. The `interim_id_token` that DTR can return during the Deferred Code Exchange Response is also worth noting for Mission deployments. When the OP can partially verify identity before the full authentication process completes, it can include an interim ID Token with partially-verified claims. For Mission bootstrap, this opens a preliminary pattern: a partially-verified identity could authorize a provisional Mission Proposal with restricted scope, upgraded to a full Mission once complete identity verification returns. That pattern is optional, but a deployment profile for high-assurance Mission types should address whether provisional Missions are permitted and what their authority bounds look like. AAuth's `202 Accepted` pending state is the native equivalent of DTR's deferred flow. In AAuth, deferred approval with a polling URL is a first-class part of the core protocol. In the OpenID Connect world, DTR is the spec that adds this capability. Part 3 of this series notes AAuth's native deferred approval as an advantage over standard OAuth for agent Mission bootstrap. DTR is the OIDC ecosystem's answer to that gap. It does not make the OIDC path as seamless as AAuth's native flow, but it does mean the deferred-approval shape exists without requiring a protocol change, for deployments that need to stay in the OpenID Connect world. # The ID-JAG Payoff So far the story covers the home domain. The interesting case is when the Mission needs to cross into another authorization domain inside the same enterprise, specifically one that trusts the same OP but issues its own tokens. In the scheduling scenario, the calendar and email services might sit behind one Resource AS. The CRM sits behind another. Both trust the same enterprise IdP. Token exchange can bridge this gap, but there is a cleaner option when same-IdP trust already exists: the OP can issue an ID-JAG carrying a reduced Mission projection, and the downstream Resource AS can validate it directly. The ID-JAG is not the Mission traveling across the boundary. It is a signed assertion, issued by the OP the downstream AS already trusts, that carries a minimal projection: the `mission` claim, the applied `purpose.kind`, the relevant expiry, and actor context only if that information is needed and trustworthy enough for the receiving policy. The downstream AS validates the assertion, binds the `mission.id` and `mission.origin` into its local token or server-side token state, and issues an audience-specific access token scoped to its own resources. What the projection carries, and what it deliberately omits, matters. It should include `mission.id`, `mission.origin`, the `purpose.kind`, audience-relevant params, expiry bounds, and actor context only when the receiving AS needs it for policy evaluation and can interpret its trust level correctly. It should not include the full applied `client_context`, UI-only display fields, parameters irrelevant to the receiving audience, or the internal Mission Authority Model. The downstream AS gets what it needs to issue a correctly bounded token. It does not get a copy of the governing Mission. > The right mental model is not "the mission lives in the ID-JAG." It is "the ID-JAG carries a reduced Mission projection inside a trust domain that already trusts the OP as an assertion source." This is where the profile becomes compelling as a whole. The user authenticated once, the OP applied a purpose context, and that applied context bootstrapped a Mission. The same-IdP trust that already exists in the enterprise becomes the carrier for a minimal Mission projection. No new bilateral trust establishment. No new protocol. Just the enterprise's existing federation infrastructure carrying a narrowly scoped assertion that lets downstream ASes issue correctly bounded tokens under the same Mission. # End-to-End Protocol Flow The scheduling scenario, calendar, email, and CRM, has three authorization domains behind the same enterprise IdP. Here is how the protocol messages flow. **Phase 1: Authentication and Mission bootstrap** The agent initiates an OIDC authentication using Pushed Authorization Requests ([PAR, RFC 9126](https://datatracker.ietf.org/doc/html/rfc9126)) to keep the `client_context` payload out of the browser URL. The `client_context` parameter carries the structured purpose context as a JSON object: ```http POST /par HTTP/1.1 Host: idp.example.com Content-Type: application/x-www-form-urlencoded Authorization: Basic response_type=code &client_id=ai-assistant &redirect_uri=https://assistant.example.com/callback &scope=openid &nonce=n-0S6_WzA2Mj &client_context={ "contexts": { "purpose": { "kind": "https://example.com/purposes/schedule-meeting", "display": { "title": "Schedule Meeting", "description": "Schedule a meeting with the engineering team and record the follow-up" }, "params": { "calendar": "engineering@example.com", "date_range": "2026-04-01/2026-04-08" }, "actor": { "type": "agent", "id": "assistant-agent-v2", "sub": "user-123" } } } } ``` The OP evaluates the purpose class against policy, presents purpose information to the user using the supplied `display` values or OP-generated text, applies step-up if required, and completes authentication. After the authorization code exchange, the ID Token confirms the applied context: ```json { "iss": "https://idp.example.com", "sub": "user-123", "aud": "ai-assistant", "nonce": "n-0S6_WzA2Mj", "client_context": { "contexts": { "purpose": { "kind": "https://example.com/purposes/schedule-meeting", "params": { "calendar": "engineering@example.com", "date_range": "2026-04-01/2026-04-08" }, "actor": { "type": "agent", "id": "assistant-agent-v2" } } } }, "exp": 1773072600 } ``` The OP or associated AS uses the applied `client_context` to create the Mission. Internally the AS records the Mission, and the projected protocol-facing handle is the `mission` object: `{ "id": "msn_7M9Qx2", "origin": "https://as.example.com" }`. That verification step matters. A client cannot safely treat the `client_context` it sent in the request as proof that the OP applied it. It has to verify the signed ID Token, check that the `client_context` claim is actually present, and reject the flow if required context is absent or inconsistent. Mission bootstrap only works if the applied context is carried in the signed ID Token and verified by the client. **Phase 1b (variant): Deferred Mission bootstrap** When the purpose type requires identity verification or human approval that cannot complete in a single session, the agent uses the `deferred_code code` response type instead. The PAR request is identical except for `response_type`: ```http POST /par HTTP/1.1 Host: idp.example.com Content-Type: application/x-www-form-urlencoded Authorization: Basic response_type=deferred_code+code &client_id=ai-assistant &redirect_uri=https://assistant.example.com/callback &scope=openid &nonce=n-0S6_WzA2Mj &client_context={ "contexts": { "purpose": { "kind": "https://example.com/purposes/schedule-meeting", "display": { ... }, "params": { "calendar": "engineering@example.com", "date_range": "2026-04-01/2026-04-08" }, "actor": { "type": "agent", "id": "assistant-agent-v2", "sub": "user-123" } } } } ``` The OP determines this purpose class requires human approval before Mission authority can be granted. It redirects back with a `deferred_code` instead of a `code`: ``` HTTP/1.1 302 Found Location: https://assistant.example.com/callback? deferred_code=SplxlOBeZQQYbYS6WxSbIA &state=af0ifjsldkj ``` The agent exchanges the `deferred_code` for a `deferred_auth_id`: ```http POST /token HTTP/1.1 Host: idp.example.com Content-Type: application/x-www-form-urlencoded Authorization: Basic DPoP: grant_type=urn:openid:params:grant-type:deferred &deferred_code=SplxlOBeZQQYbYS6WxSbIA &deferred_notification_token=8d67dc78-7faa-4d41-aabd-67707b374255 ``` ```json { "deferred_auth_id": "f4oirNBUlM", "expires_in": 10800, "interval": 60 } ``` The agent polls at the configured interval. Until the approval decision is made, the OP returns `authorization_pending`. When the human reviewer approves the Mission Proposal, the next poll returns a successful Token Response: ```json { "access_token": "...", "token_type": "DPoP", "id_token": "", "expires_in": 3600 } ``` If the RP registered a `deferred_client_notification_endpoint`, the OP sends a ping callback when the decision is made rather than requiring indefinite polling: ```http POST /callback HTTP/1.1 Host: assistant.example.com Authorization: Bearer 8d67dc78-7faa-4d41-aabd-67707b374255 Content-Type: application/json { "deferred_auth_id": "f4oirNBUlM" } ``` The agent then makes one final token request to retrieve the ID Token. Both paths, synchronous and deferred, converge here: the returned ID Token contains the applied `client_context` claim in the same structure as Phase 1. The OP or associated AS uses it to create an Approved Mission, exposes its `mission.id` and `mission.origin` for derivation, and Phase 2 proceeds identically. **Phase 2: Mission-governed token derivation** With a `mission` handle in hand from either bootstrap path, the agent requests a calendar token referencing the Mission via `authorization_details`. [DPoP (Demonstrating Proof of Possession, RFC 9449)](https://datatracker.ietf.org/doc/html/rfc9449) sender-constraining is assumed throughout. ```http POST /token HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded DPoP: grant_type=authorization_code &code=SplxlOBeZQQYbYS6WxSbIA &redirect_uri=https://assistant.example.com/callback &authorization_details=[{"type":"mission","mission":{"id":"msn_7M9Qx2","origin":"https://as.example.com"}}] ``` The AS validates Mission state and issues an audience-bound access token: ```json { "iss": "https://as.example.com", "sub": "user-123", "sub_profile": "user", "aud": "https://calendar-api.example.com", "act": { "sub": "assistant-agent-v2", "sub_profile": "ai_agent" }, "mission": { "id": "msn_7M9Qx2", "origin": "https://as.example.com" }, "scope": "calendar.schedule", "cnf": { "jkt": "" }, "exp": 1773069300 } ``` The email token follows the same pattern via RFC 8693 token exchange, with `resource=https://email-api.example.com` and the calendar access token as the subject token. The AS checks Mission state at each exchange before issuing. **Phase 3: ID-JAG projection for the CRM (same-IdP)** The CRM sits behind `crm-as.example.com`, a separate Resource AS that issues its own tokens but trusts the same enterprise IdP. The agent requests a Mission-projection assertion from the OP using token exchange, identifying the target audience: ```http POST /token HTTP/1.1 Host: idp.example.com Content-Type: application/x-www-form-urlencoded Authorization: Basic grant_type=urn:ietf:params:oauth:grant-type:token-exchange &subject_token= &subject_token_type=urn:ietf:params:oauth:token-type:id_token &requested_token_type=urn:ietf:params:oauth:token-type:id-jag &audience=https://crm-as.example.com &authorization_details=[{"type":"mission","mission":{"id":"msn_7M9Qx2","origin":"https://as.example.com"}}] ``` The OP confirms the Mission is still active and the CRM audience is within the Mission's bounds, then issues the ID-JAG. This is a signed JWT carrying only what the CRM AS needs: no display fields, no full authority model, no parameters irrelevant to CRM enforcement: ```json { "iss": "https://idp.example.com", "sub": "user-123", "sub_profile": "user", "aud": "https://crm-as.example.com", "resource": "https://crm.example.com/api", "act": { "sub": "assistant-agent-v2", "sub_profile": "ai_agent" }, "mission": { "id": "msn_7M9Qx2", "origin": "https://as.example.com" }, "purpose": "https://example.com/purposes/schedule-meeting", "jti": "id-jag-8f3a2b", "exp": 1773069600 } ``` The agent presents this ID-JAG at the CRM Resource AS as a JWT bearer grant: ```http POST /token HTTP/1.1 Host: crm-as.example.com Content-Type: application/x-www-form-urlencoded DPoP: grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer &assertion= &scope=crm.notes.write ``` The CRM AS validates the signature, confirms the same enterprise IdP as issuer, and issues a CRM-scoped token: ```json { "iss": "https://crm-as.example.com", "sub": "user-123", "sub_profile": "user", "aud": "https://crm.example.com/api", "act": { "sub": "assistant-agent-v2", "sub_profile": "ai_agent" }, "mission": { "id": "msn_7M9Qx2", "origin": "https://as.example.com" }, "scope": "crm.notes.write", "cnf": { "jkt": "" }, "exp": 1773069900 } ``` The critical point is not the exact wire format. It is that the Mission remains at the AS, the OP projects only the minimum information the same-IdP domain needs, and every issued token still traces back to the same governed Mission. # Consent Fatigue Is the Failure Mode This architecture only helps if it reduces repeated user prompts rather than multiplying them. That is the real danger with any authentication-layer Mission bootstrap model. If every newly discovered tool, every downstream token exchange, or every sub-step in a long-running Mission forces the user back through another interactive approval screen, the result is not stronger governance. It is just consent fatigue. Consent fatigue breaks the model in predictable ways: - users stop reading prompts - agents get broad standing approval just to avoid interruption - teams weaken the prompts because the workflow becomes unusable - genuinely high-risk transitions become harder to distinguish from routine noise That is why this profile only makes sense on top of Mission-Bound OAuth rather than in place of it. The point of the authentication step is not to ask the user about every downstream token. The point is to create or approve a Mission once, at a moment when the user is present, and then let the authorization layer govern bounded derivations inside that approved Mission. The practical rule is simple: - use Client Context when a fresh human authentication or approval event is genuinely needed - use the Mission to carry that approval forward across bounded downstream actions - require a new user interaction only when the agent needs to go outside the approved Mission envelope If the profile cannot do that, it has failed. # RAR, Token Exchange, Client Context, and DTR These mechanisms are complementary, not competing. Client Context explains why the user is authenticating and what they are approving. Mission-Bound OAuth defines the durable authority object and lifecycle. RAR shapes resource-specific authorization requests. Token exchange derives audience-specific tokens. ID-JAG projects reduced Mission context across same-IdP trust domains. DTR makes Mission bootstrap asynchronous when the purpose type requires it. That is the layered model that makes sense for enterprise agent deployments. RAR is still the better fit when there is one authorization server, the resource domain is already tightly governed, and the main problem is the shape of the access token. Client Context plus ID-JAG adds the most value when: - a user is present - the OP is the enterprise trust anchor - the Mission spans multiple authorization domains - same-IdP trust makes assertion projection practical - authentication-time step-up and approval evidence matter DTR adds value on top of that when: - Mission bootstrap for the given purpose type cannot complete synchronously - human review of the Mission Proposal is part of the approval flow - identity verification requirements exceed what a single interactive session can confirm - the RP needs a notification model rather than a blocking wait [GNAP (RFC 9635)](https://datatracker.ietf.org/doc/html/rfc9635) is worth acknowledging here too. It addresses multi-resource delegation with a different architectural model and does not depend on the same shared-IdP assumption. For greenfield systems, that may be the cleaner direction. This post is about how to improve the world enterprises actually have today. # What This Companion Profile Needs To Define Client Context plus ID-JAG is enough to improve Mission bootstrap, but it only becomes a real companion profile when the handoff and projection rules are explicit. So rather than leave those pieces as open questions, here is the profile definition that seems to fit this architecture. ## 1. Client Context To Mission Handoff Profile The base Client Context draft intentionally stops at the authentication layer. It defines requested context, applied context, and client verification, but it does not define the server-side object that applied context might instantiate. This profile closes that seam by treating the Mission as the target object. ### Handoff Preconditions Before any Mission is created, approved, or resumed from an interactive authentication event, all of the following have to be true: - The client has validated the ID Token normally, including signature, issuer, audience, expiration, and `nonce`. This prevents Mission bootstrap from hanging off an untrusted authentication result. - The ID Token contains a `client_context` claim. This ensures the OP actually returned applied context. - The client has verified that the returned `client_context` contains the required applied context for the operation it is about to enable. This prevents the client from treating requested context as if it were applied context. - The OP or associated Mission service treats only the applied `client_context` from the ID Token as Mission input, never the raw request value. This ensures Mission creation is rooted in confirmed, signed context rather than client-supplied request data. If those conditions are not met, no Mission bootstrap occurs. ### Handoff Modes This profile defines three handoff modes: | Mode | When it applies | Result | |---|---|---| | `Create` | No active Mission handle is associated with the interaction | The OP or associated Mission service uses the applied context to create a new Mission | | `Approve` | Local policy requires explicit approval of a pre-created or pending Mission | The OP or associated Mission service uses the applied context and the authenticated subject to mark that Mission approved | | `Resume` | The client presents an existing `mission.id` and `mission.origin`, and the Mission is still active | The OP or associated Mission service may treat the authentication event as a Mission re-attestation, but only if the applied context is compatible with the stored Mission record | The profile should fail closed here: if the Mission service cannot determine whether the event is a create, approve, or resume operation, it rejects the handoff. In shorthand, the decision flow looks like this: ```text No Mission handle? -> Create Pending or pre-created Mission? -> Approve Existing active Mission handle? -> Resume Anything ambiguous? -> Reject ``` ### Mapping Applied Context Into Mission Inputs The handoff takes the applied context and maps it into Mission inputs with a strict split between governance inputs and audit-only inputs. | Category | Contents | How it is used | |---|---|---| | Governance inputs | `purpose.kind`, validated `params`, applied tenant or application identifiers, authenticated subject, authentication strength such as `acr` where relevant, and validated temporal bounds such as `constraints.expires_at` or `constraints.max_duration` | Compiles into the Mission Authority Model | | Audit and evidence inputs | The applied context envelope, authentication time, any rendered or canonicalized display evidence retained by the OP, and any actor information the OP has verified or explicitly retained as advisory | Supports audit, traceability, and evidence retention | | Never authority by themselves | Raw request `client_context`, unverified `actor` values, and UI-oriented text such as `display.title` or `display.description` | Must not define what the system is authorized to do | That split matters. `purpose.kind` and validated `params` can shape the Mission Authority Model; the display text can help explain what happened, but it must not define what the system is authorized to do. ### Purpose Catalog Requirement This profile depends on a purpose catalog keyed by `purpose.kind`. For each supported `purpose.kind`, the catalog needs to define: - The schema for `params`. This defines what instance inputs are valid. - Which `params` members are Mission-governing versus audit-only. This separates authority-shaping data from evidence-only data. - Allowed tenants, applications, or resource classes, where relevant. This constrains where the Mission may apply. - Required authentication strength or step-up rules. This tells the OP what assurance level is needed. - Maximum lifetime and propagation rules. This limits duration and downstream spread. - Conditions for resume versus recreate. This determines when a Mission can be re-attested rather than re-issued. This is what allows applied context to compile into a bounded Mission instead of becoming just another bag of metadata. ### Failure Semantics If authentication succeeds but Mission compilation or policy evaluation fails, the profile should treat that as a Mission bootstrap failure, not as a soft success. ```text Authentication succeeds Mission compilation fails -> No Mission created / approved / resumed -> Client does not enable the Mission-bound operation -> Failure is surfaced distinctly from ordinary authentication failure ``` That is the only safe behavior. "The user authenticated successfully" is not equivalent to "Mission bootstrap succeeded." ## 2. Mission Projection Profile For ID-JAG Once a Mission exists, same-IdP propagation needs a stable projection model. This profile defines ID-JAG as a reduced, audience-bound Mission projection, not as a portable copy of the Mission itself. ### Projection Model | This projection is | This projection is not | |---|---| | A Mission already governed at the home authorization server | The full Mission Authority Model | | A projection for one specific downstream audience | The full applied `client_context` | | A reduced set of Mission-derived facts that the downstream AS can evaluate locally | UI text shown to the user | | An input to local downstream token issuance | Advisory values the downstream AS cannot safely interpret | ### Minimum Projection Claims At minimum, the projected assertion should carry: - `iss`: identifies the OP issuing the assertion. - `aud`: binds the projection to exactly one downstream AS audience. - `sub`: carries the authenticated user subject. - `mission`: carries the stable protocol-facing Mission handle as `id` and `origin`. - `purpose` or `purpose_kind`: carries the applied `purpose.kind`. - `iat` and `exp`: bound issuance time and lifetime. - `jti`: supports replay detection. The assertion MAY also carry: - Minimized audience-relevant `params`. Include these only when they are needed for downstream issuance policy. - Actor information. Include it only when the issuer can state whether it is verified or advisory and the receiver has policy for that distinction. - Sender-constraining information such as `cnf`. Include it when the deployment binds assertions or derived tokens to a proof-of-possession key. ### Projection Minimization Rules The profile should define strict minimization rules: | Do not include | Reason | |---|---| | The full applied `client_context` | Too broad for audience-specific projection | | `display` content | UI evidence is not needed for downstream issuance | | `params` members irrelevant to the downstream audience | Violates minimization and increases leakage | | Mission-internal authority structure, workflow state, or extra lifecycle metadata | The downstream AS needs issuance facts, not a copy of Mission internals | The projection should answer one narrow question for the downstream AS: what Mission-scoped facts does this AS need to issue a correctly bounded local token? In practice, the boundary looks like this: | Value | Stay local to home AS / Mission service | May cross domains in projected form | |---|---|---| | Mission Authority Model | Yes | No | | Full applied `client_context` | Yes | No | | `display` content | Yes | No | | `mission.id` and `mission.origin` | No | Yes | | Applied `purpose.kind` | No | Yes | | Audience-relevant `params` | Usually | Yes, but only minimized | | Actor data | Usually | Only when needed and with clear trust semantics | | Workflow state / internal lifecycle details | Yes | No | ### Downstream AS Processing The downstream AS validates the assertion and then makes a fresh local issuance decision. At minimum it should: ```text Validate signature, issuer, audience, time validity, and replay protections Confirm the issuer is trusted for Mission projection into this audience Apply local policy to mission.id, mission.origin, purpose.kind, minimized params, and actor information Reject if projected values exceed local policy, even if the assertion is otherwise valid ``` The downstream AS does not inherit the Mission wholesale. It receives enough projection to mint its own audience-bound token under local policy. ### Projection Failure Semantics If the projection is invalid, expired, replayed, insufficiently trusted, or outside local policy, the downstream AS rejects it and issues no token. That rejection should not be treated as proof that the home Mission is invalid. It only means that this downstream domain will not honor this projection under its own policy. ## What Mission-Bound OAuth Now Defines The remaining piece, actor verification and execution continuity, now sits where it belongs: in [Mission-Bound OAuth](/notes/mission-bound-oauth/#verified-agent-binding). The latest Client Context draft is right to treat `actor` as advisory by default. That protects the authentication-layer protocol from over-claiming trust it has not earned. But Mission-Bound OAuth needs more than advisory actor context. It has to answer the separate question of whether the actor executing derived actions is the same actor the Mission approved at bootstrap. The Mission-Bound OAuth draft now defines that as **verified agent binding**. In that model: - the Mission record at the AS is the binding anchor - sender constraining provides key continuity across derivation steps - the AS performs actor verification at token exchange time - derived actor claims are AS-authoritative rather than client-self-asserted - cross-domain projection carries actor context, but live actor continuity across trust domains still depends on introspection or equivalent state sharing That is the right split. Client Context and ID-JAG handle authentication-time bootstrap and reduced projection. Mission-Bound OAuth handles authority continuity across the Mission lifecycle. # How This Closes The Security Gaps Those profile pieces are not just interoperability work. They are how the architecture closes its remaining security gaps. The main security gaps still open are these: - **Bootstrap/request confusion.** The client must verify applied context in the ID Token before treating a Mission as user-rooted. The profile now says that explicitly, but the handoff profile must make it impossible for Mission creation to rely on unverified request data. - **Actor substitution.** Advisory `actor` data is not enough for high-stakes delegation. The Mission-Bound OAuth draft now addresses this with verified agent binding, so the remaining gap here is making sure this companion profile depends on that model rather than trying to redefine it. - **Projection over-sharing.** ID-JAG needs minimization rules so deployments do not dump the full applied context, UI text, or broad `params` objects into downstream assertions. - **Replay and confused deputy risk.** Projection claims have to be audience-bound, time-bounded, replay-resistant, and tied to local policy evaluation at the downstream AS. Otherwise one resource domain can be tricked into honoring context intended for another. - **Lifecycle drift.** If a Mission is suspended, revoked, or terminated, projections and derived tokens need coherent invalidation behavior. Otherwise Mission lifecycle becomes an aspiration rather than an enforcement property. That is fundamentally a Mission-Bound OAuth responsibility, even if this profile depends on it. These are exactly the kinds of gaps that appear when governance lives in one object, authentication evidence in another, and downstream assertions in a third. They are solvable, but only if the profile makes the joins explicit. # What Open-World Agents Still Require The hardest requirement is still the original one: making open-world agents possible without turning the Mission into a standing blanket approval. That requires more than authentication-time bootstrap. It requires a bounded discovery model. At Mission creation time, the system has to be able to say something stronger than "this one exact API and scope are allowed" and something narrower than "the agent may do whatever seems related." In practice, that means the profile needs a purpose catalog that defines, for each `purpose.kind`: - the schema of allowed `params` - the classes of downstream resources the agent may discover at runtime - the operations that are in-family for that purpose - the maximum privilege, lifetime, and propagation rules for those operations - the boundary where newly discovered work is no longer considered part of the approved Mission That lets the Mission service compile a Mission Authority Model that is tight enough to govern real execution while still giving the agent room to discover concrete resources at runtime. The missing rule is the re-approval boundary. An open-world agent should be able to keep working when it discovers a new calendar folder, a new mailbox, or a new CRM record that is still inside the approved purpose class and parameter bounds. It should not be able to silently expand into a different subject, a different tenant, a stronger operation, a different resource class, or a longer-lived execution than the compiled Mission allows. At a high level, the boundary should work like this: | Newly discovered change | Stay inside Mission | Require re-approval | |---|---|---| | Another object of the same allowed resource class | Yes | No | | Same subject, same tenant, same operation class | Yes | No | | New subject outside approved bounds | No | Yes | | New tenant | No | Yes | | Stronger operation than the compiled Mission allows | No | Yes | | Different resource class outside purpose policy | No | Yes | | Longer lifetime or broader propagation than allowed | No | Yes | So the complete model needs a deterministic answer to one question: > Is this newly discovered action still inside the Mission envelope, or does it require a fresh human interaction? If the system cannot answer that question mechanically, then open-world execution collapses back into either over-broad standing authority or repeated consent prompts. That is why the real end state is not "put more data in Client Context." It is a cleaner division of labor: - Client Context bootstraps purpose at authentication time - the handoff profile compiles applied context into a bounded Mission - Mission-Bound OAuth governs that Mission across downstream derivations - ID-JAG projects only the minimum necessary Mission view across same-IdP trust domains - Mission-Bound OAuth ensures the executing actor is the actor the system approved - re-approval triggers fire automatically when discovery crosses the compiled Mission boundary That is the architecture that closes the remaining security gaps and makes open-world agents plausible without giving them permanent ambient authority. # The Practical Claim The claim here is not that Client Context solves agent security. The claim is narrower: Client Context is a strong way to capture and confirm interactive Mission bootstrap input at authentication time, and ID-JAG is a strong way to project reduced Mission context across same-IdP trust domains, while leaving the durable Mission and its lifecycle where they belong: at the authorization server. That is a smaller claim than "mission in the ID Token." It is also a much better architecture. --- If you work in identity, security architecture, or agent systems and are thinking about how to carry mission context through the authentication layer, the questions I care most about are: - what should a Client Context to Mission handoff look like in a real profile - what minimum Mission projection belongs in an ID-JAG - where same-IdP projection stops being enough and a broader Mission assertion profile is needed The Client Context draft is at [github.com/mcguinness/connect-client-context](https://github.com/mcguinness/connect-client-context). --- # Mission-Bound OAuth Canonical URL: https://notes.karlmcguinness.com/notes/mission-bound-oauth/ Markdown URL: https://notes.karlmcguinness.com/notes/mission-bound-oauth.md This document is a working item for iterating on the architecture before drafting one or more IETF Internet-Drafts. The current working name is `draft-mcguinness-oauth-mission-bound-authorization`. This is a **RFC**: an end-to-end architecture proposal published to gather feedback before the work is split into standards-track core pieces, companion specs, or deployment profiles. It is intentionally a **superset architecture document**. It describes the full model, even where different parts may eventually be standardized separately or left as implementation guidance. The goal is to make the design legible enough for identity and OAuth practitioners to react to the whole system before the work is narrowed into concrete drafts. If the architecture holds up, the likely next step is to split it into a smaller core OAuth draft plus companion profiles. If you want the shortest version of the argument, it is this: - OAuth is good at point-in-time authorization. - Agents need authority that survives across token lifetimes. - That authority needs purpose, lifecycle, delegation bounds, and independent termination. - [Mission-Bound OAuth](#architecture-overview) proposes a durable [Mission](#key-terms) object at the Authorization Server to provide that layer. If you want the shortest version of what is new here, it is this: - a [Mission](#key-terms) is a durable delegated-authority object at the AS, not just another token claim - tokens derive from the Mission; they do not define it - Mission lifecycle is independent of token lifetime - Mission state can terminate execution because the business purpose ended, not only because a token expired - Mission-Bound OAuth is designed to fit existing OAuth, policy, gateway, and FGA deployments rather than replace them If you are skimming, read these sections first: - [Introduction](#introduction) for the problem and core claim - [Architecture Overview](#architecture-overview) for the model in one pass - [Worked Example: Scheduling Assistant](#worked-example-scheduling-assistant) for the end-to-end flow - [Deployment Pattern Examples](#deployment-pattern-examples) for how this fits gateways, RS policy, and FGA - [Practical Limits and Realistic Claim](#practical-limits-and-realistic-claim) for where this architecture can fail - [Open Questions](#open-questions) for what is genuinely unresolved What this is not: - not a claim that OAuth should become a workflow engine - not a replacement for AuthZEN, FGA, MCP, or GNAP - not a universal policy language - not a promise of perfect real-time termination - not a requirement that every resource server become Mission-aware on day one # Introduction OAuth is good at issuing tokens that represent authorization at a moment in time for a client, audience, and scope. Agentic systems need something stronger and longer-lived than that, but also more bounded than standing credentials. An agent may: - interpret a user prompt - plan a multi-step mission - call multiple APIs over time - delegate sub-tasks to other software components - resume work after pauses or human approvals Standard OAuth primitives do not directly model the delegated authority that makes those actions legitimate as a coherent whole. Access tokens are audience-bound and short-lived by design. Refresh tokens extend continuity, but they do not encode mission purpose, delegation boundaries, or lifecycle state in a way that an authorization server can govern as a first-class artifact. The core design objective is therefore: > represent agent authority as an approved, bounded, persistent authorization context tied to mission purpose and lifecycle, rather than as raw credential possession. This is closer to [power-of-attorney](https://notes.karlmcguinness.com/series/you-dont-give-agents-credentials-you-grant-them-power-of-attorney/) than to passport-style authentication. OAuth is increasingly being used in environments where software does more than make a single API call on behalf of a user. Agents plan, pause, resume, delegate, and cross service boundaries. That creates a gap between what existing OAuth tokens represent and what operators actually need to control. What is missing is not another broad token. What is missing is a durable, governable authority object for a delegated mission: - approved once - constrained over time - checked again at each derivation step - revocable independently of token expiry - understandable across audit, policy, and delegation boundaries Mission-Bound OAuth is an attempt to define that object and show how OAuth can use it without abandoning its existing model. In the terminology of the Power of Attorney series, the [Mission](#key-terms) is the architecture and protocol evolution of what the series called an [Execution Mandate](https://notes.karlmcguinness.com/from-passports-to-power-of-attorney/). The practical claim is intentionally narrow. This RFC is not arguing that OAuth should become a workflow engine, or that [Mission-Bound OAuth](#architecture-overview) solves all of agent security. The claim is that a durable [Mission](#key-terms) object at the AS would let existing OAuth deployments govern delegated machine authority more safely than token-only patterns do today. # Terminology and Roles ## Key Terms | Term | Definition | |---|---| | **Mission** | An AS-maintained authorization object representing approved delegated authority for a specific purpose. It has lifecycle state, an authority model, delegation bounds, and can be terminated independently of any token. | | **Mission Proposal** | A candidate authority description submitted to the AS for review. Not yet authoritative. May be produced from a prompt, intent envelope, MCP tool schema extraction, or structured request. | | **Approved Mission** | The governance artifact created when a proposal is accepted. Authoritative from a business and governance perspective; holds the lifecycle constraints and audit record of who approved what. | | **Mission Authority Model** | The machine-evaluable authority representation derived from the Approved Mission. Authoritative for token issuance, token exchange, gateway checks, and RS policy decisions. Stored as a signed, versioned artifact at the AS. | | **Projected Mission artifacts** | Reduced views of Mission state emitted at protocol boundaries: token claims, introspection responses, cross-domain assertions, audit events. Expose only the minimum data needed at each boundary. | | **`mission_id`** | The AS-internal authoritative identifier of a Mission record. Not exposed at protocol boundaries. | | **`mission_ref`** | The projected Mission reference handle used at protocol boundaries: tokens, token exchange, introspection, cross-domain assertions. It is derived from the AS-internal Mission record but is treated as a distinct external handle. | | **Mission Lifecycle** | The set of states a Mission passes through: `active`, `suspended`, `completed`, `revoked`, `expired`. Missions are created in `active` state upon proposal approval. Enforced by the AS before every token issuance, refresh, token exchange, and delegation event. | | **Authority Region** | The bounded set of resources, operations, selectors, predicates, and constraints represented inside a Mission Authority Model. | | **Authority Compilation Boundary** | The architectural boundary between ambiguous intent (prompt or plan) and enforceable delegated authority (Mission Authority Model). Mission approval is the trust boundary between the two. | | **Intent Envelope** | An intermediate structured representation of what an agent intends to do, derived from prompt interpretation. Proposal input, not authority. | | **Mission Template** | A pre-registered authority pattern for a common mission category. Templates constrain how proposals become Missions and define the default authority model for a purpose class. | | **Purpose Class URI** | A URI-form stable identifier for a Mission class, used in client registration, policy rules, and audit. Example: `urn:example.com:mission:schedule-meeting`. | The design currently assumes the following logical roles: | Role | Responsibility | Notes | |---|---|---| | **User** | Principal on whose behalf authority is granted | Often the subject, but not always the only approver | | **Agent Client** | Software component that interprets the prompt and executes the Mission | May also be the OAuth client | | **Orchestration Layer** | Platform or runtime that manages agent execution and calls the Mission proposal endpoint on behalf of the agent | May collapse into the Agent Client in simpler deployments | | **Authorization Server (AS)** | Stores Mission state and issues OAuth artifacts | Remains authoritative for Mission state used by OAuth | | **Resource Server (RS)** | API being accessed | May be Mission-aware or Mission-agnostic | | **Resource Authorization Server (Resource AS)** | In cross-domain deployments, validates Mission assertions and issues audience-specific tokens for a governed trust domain | May differ from the AS that issued the original Mission | | **Approver** | Human or policy actor that can approve, reject, or attenuate a proposed Mission | Can be user, admin, or policy-driven | | **Policy Decision Point (PDP)** | Optional policy engine used to evaluate constraints and access conditions | Often integrated via AuthZEN-style interfaces | Some deployments may collapse these roles. The protocol should not assume they are always distinct implementations. ```text +----------+ | User | +---+--+---+ | | interprets | | (may serve prompt | | as Approver) v | +----------+--+ +----------+ |Orchestration | | Approver | | Layer | +----+-----+ +------+-------+ | | | proposal | approval / submission | attenuation | | +-------+-------+ | v +---------+---------+ | Authorization |<------>[PDP] | Server | +---------+---------+ | OAuth auth + token exchange | v +---------+---------+ | Agent Client | +---------+---------+ | mission-bound access token | v +---------+---------+ | Resource Server | +----+----------+---+ | | cross-domain | introspect (optional) v v +--------+--+ +---+-----------+ |Resource | |Authorization | |Auth Server | | Server | +-----------+ +---------------+ ``` ## Subject and Actor Model IAM readers will reasonably ask "who is who?" because Mission-Bound OAuth spans multiple identity and authority roles that normal OAuth deployments often blur together. At minimum, the model should distinguish: - **subject**: the principal on whose behalf authority is being exercised - **client**: the OAuth client or orchestration layer requesting tokens and Mission operations - **agent runtime**: the software component performing planning or execution for the client - **active actor**: the component currently using a derived token at a given hop - **approver**: the principal or policy authority that can approve, attenuate, suspend, resume, or revoke a Mission The clean mapping is: - `sub` identifies the subject on whose behalf the Mission exists - `client_id` identifies the registered client or orchestration layer - `act` represents the active delegated actor chain for token-based delegation - Mission audit events capture the approver or administrative actor that changed Mission state This matters because approval authority, delegated execution, and audit attribution are different concerns. They should not collapse into a single identifier model. # Background and Related Work This document does not appear in a vacuum. It builds on a line of argument developed in the three-part series [You Don't Give Agents Credentials. You Grant Them Power of Attorney](https://notes.karlmcguinness.com/series/you-dont-give-agents-credentials-you-grant-them-power-of-attorney/): - [Agents Don't Need Your Passport. They Need Your Authority](https://notes.karlmcguinness.com/agents-dont-need-your-passport-they-need-your-authority/) frames the structural gap: identity, access control, and delegation can all work correctly while no layer asks whether a delegated mission should still be running at all. - [From Passports to Power of Attorney](https://notes.karlmcguinness.com/from-passports-to-power-of-attorney/) introduces the authority-governance model behind this work: purpose, scope, conditions, lifecycle, and delegation as a governed artifact rather than something implied by credentials. - [Governing the Stay, Not Just the Entry](https://notes.karlmcguinness.com/governing-the-stay-not-just-the-entry/) explains why revocation, continuous evaluation, and business-event termination have to be first-class if delegated machine authority is to remain governable over time. The series used the term `Execution Mandate` for that governed artifact. This RFC uses `Mission` as the protocol-facing term, but the underlying idea is the same: delegated machine authority must be represented as a governed object, not inferred from token possession alone. This architecture also sits alongside adjacent work in the identity and authorization ecosystem: - [RFC 9396: OAuth 2.0 Rich Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9396) for structured authorization input at token issuance time. - [RFC 8693: OAuth 2.0 Token Exchange](https://datatracker.ietf.org/doc/html/rfc8693) for downstream token derivation and delegation checkpoints. - [RFC 9635: GNAP](https://www.rfc-editor.org/rfc/rfc9635) as the cleaner-sheet alternative to extending OAuth for richer delegated authorization semantics. - [OpenID Authorization API 1.0](https://openid.net/specs/authorization-api-1_0.html) as the current AuthZEN decision interface for PDP/PEP integration. - [OpenID Shared Signals Framework 1.0](https://openid.net/specs/openid-sharedsignals-framework-1_0-final.html) and [OpenID Continuous Access Evaluation Profile 1.0](https://openid.net/specs/openid-caep-1_0-final.html) for state change propagation and event-driven termination. - [Model Context Protocol](https://modelcontextprotocol.io/specification/) for tool and context discovery above the authority layer. - [OAuth 2.0 Transaction Tokens](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-transaction-tokens-08) for context propagation in trusted domains. - [NIST NCCoE Software and AI Agent Identity and Authorization](https://www.nccoe.nist.gov/projects/software-and-ai-agent-identity-and-authorization) as evidence that this problem space is active and recognized outside vendor marketing. Mission-Bound OAuth is intended to complement, not replace, these efforts. The claim is narrower: existing OAuth and policy building blocks still leave a gap around durable delegated mission governance, and that gap becomes visible once agents operate beyond point-in-time authorization decisions. The existing authorization landscape provides two models, each useful in its domain: **OAuth scopes** represent flat permissions at a point in time. They are well-understood, widely deployed, and appropriate for single-request authorization. They have no lifecycle concept and no [Mission](#key-terms) identity. **Rich Authorization Requests (RAR, RFC 9396)** extend scopes with structured permission objects. They allow richer description of what a token permits at a specific audience. They remain point-in-time: each token request is independent. RAR does not define a persistent authority object, so any deployment that wants one invents private, non-interoperable semantics to do so. [Mission-Bound OAuth](#architecture-overview) is standardizing what a well-designed agentic RAR deployment would build anyway, and making that persistent authority model interoperable across implementations. **[Mission-Bound OAuth](#architecture-overview)** introduces a third model: durable, governed, lifecycle-aware authority for a [Mission](#key-terms) that outlives any individual token. The critical properties that distinguish a Mission from the existing models: - A Mission is created once, before token issuance, through an approval process. - It persists as a first-class artifact at the Authorization Server across the entire Mission lifecycle. - Tokens derive authority from the Mission; the Mission does not derive from tokens. - The Mission can be suspended or terminated independently of whether any token is currently valid. - Termination can be triggered by a business event, not only by a clock. - Audit trails attach to the Mission, not to individual tokens, giving a complete record of delegated execution. > A token answers "is this request permitted right now?" A Mission answers "should this delegated mission be running at all?" These are different questions and the existing stack has no standard answer to the second. The word "durable" is the load-bearing term. A refresh token is also durable in the sense that it persists, but it is a credential artifact, not a governed authority artifact. A Mission is the authoritative record of purpose, constraints, and lifecycle state that governs every token the mission will ever produce. # Architecture Overview Mission-Bound OAuth introduces a new authorization object, the **Mission**, maintained by the AS. A Mission is the authoritative record of: - what mission purpose was approved - what bounded authority region the mission is allowed to operate within - what constraints, selectors, and predicates govern runtime decisions - how long the authority lasts - whether delegation is allowed - what lifecycle state the mission is in OAuth tokens do not replace the Mission. They derive authority from it and reference it using a projected Mission reference. The AS remains the system of record for mission state and evaluates that state before issuing, refreshing, or exchanging tokens. ## From Intent to Enforceable Authority The most important architectural question is how an open-ended user request becomes something a system can actually enforce. For open-world agents, the answer cannot be: - interpret the prompt - guess the exact future API calls - whitelist them up front That only works in tightly closed execution patterns. It does not work well when agents can discover tools dynamically, plan adaptively, encounter new resources at runtime, or operate across large enterprise systems. The architecture therefore needs an intermediate pipeline: 1. **intent input**: prompt, plan, Model Context Protocol (MCP) tool context, and surrounding mission context 2. **mission proposal**: a candidate authority description for the task 3. **constraint shaping**: templates, policy, approval, attenuation, and business rules narrow the proposal 4. **compiled authority model**: the Mission becomes a machine-evaluable authority region 5. **runtime decision inputs**: issuance, exchange, gateway, and RS checks evaluate requests against that region This is the real architectural job of a Mission. It is not just a label attached to a token. It is the compilation boundary between ambiguous intent and enforceable delegated authority. ```text prompt / plan / MCP context | v Mission Proposal | v templates + policy + approval + attenuation | v Approved Mission | v Mission Authority Model | +-> token issuance / refresh +-> token exchange +-> gateway / RS checks +-> audit / eventing ``` That boundary is especially important for open-world agents: - they may not know all resources in advance - they may discover tools at runtime - they may need to adapt plans based on what they find - but they still need bounded authority Mission-Bound OAuth provides that bounded authority model without requiring every future action to be enumerated up front. ## Authority Compilation Boundary If Missions are the bridge from open-world intent to enforceable authority, then the architecture needs to say where that bridge is built. There are at least three plausible models: - **AS-owned compilation**: the Authorization Server itself compiles proposals, templates, policy bindings, and approval outputs into the authoritative Mission representation - **mission-management service compilation**: a separate control-plane service compiles the Mission and the AS consumes the result as authoritative input for OAuth processing - **hybrid compilation**: a management service produces an intermediate form and the AS performs final normalization or binding at approval and issuance time The current bias is that the AS must remain authoritative for the Mission representation that governs token issuance, refresh, exchange, and lifecycle, even if upstream authoring and compilation are delegated to another component. That gives the architecture a clean trust boundary: - authoring may happen elsewhere - proposal shaping may happen elsewhere - policy evaluation may be externalized - but the AS remains authoritative for the Mission artifact that OAuth relies on **Mission management service trust**: when a separate mission-management service compiles Missions and submits them to the AS, the AS MUST NOT accept the proposed authority model as-is without independent validation. Compromise of the mission-management service must not be equivalent to compromise of Mission governance. The required trust model: - the mission-management service signs proposed authority-model artifacts using a key registered with the AS at service registration time - the AS verifies the signature before accepting any proposed Mission Authority Model artifact - the AS re-derives and re-validates all policy-bound predicates (lifecycle bounds, delegation limits, purpose class authorization) against its own registered policy at the time of acceptance, regardless of what the submitted artifact asserts - the AS is the final authority for the Mission Authority Model stored at the AS; a submitted artifact is a proposal input, not an authoritative record This means a compromised mission-management service can submit invalid proposals, which the AS will reject, but cannot unilaterally create an authorized Mission Authority Model. ## Mission Artifact Stack The architecture is easier to reason about if the different Mission-shaped artifacts are named explicitly. | Artifact | Purpose | Authority Status | Typical Consumers | |---|---|---|---| | **Mission Proposal** | Candidate authority description produced from prompts, plans, templates, MCP-derived tool hints, and surrounding context | Not yet authoritative; subject to approval and attenuation; may be incomplete or ambiguous | approval systems, policy checks, mission management | | **Approved Mission** | Governance artifact created once a proposal has been accepted by the relevant approver and policy controls | Authoritative from a business and governance perspective; durable record of who approved what and under which lifecycle constraints | Authorization Server, audit, governance systems | | **Mission Authority Model** | Machine-evaluable authority representation derived from the Approved Mission | Authoritative for issuance, exchange, gateway, and RS policy decisions | Authorization Server, PDPs, gateways, mission-aware resource servers | | **Projected Mission artifacts** | Reduced views of Mission state emitted at other protocol boundaries | Boundary-specific projections only; should expose the minimum needed data | tokens, introspection responses, cross-domain assertions, audit events | The relationship between these artifacts is: ```text Mission Proposal -> Approved Mission -> Mission Authority Model -> projected artifacts for tokens, introspection, assertions, and audit ``` Another view of the same stack is: ```text authoring Mission Proposal | v governance Approved Mission | v enforcement Mission Authority Model | +-> token claims +-> introspection +-> assertions +-> audit events ``` The same stack is easier to scan if you view it as a transformation pipeline: ```text [Proposal] requested authority, still ambiguous | v [Approved Mission] governance record, durable business authority | v [Mission Authority Model] machine-evaluable enforcement artifact | v [Projected Artifacts] boundary-specific token, introspection, assertion, and audit views ``` Or in compact form: | Stage | Main question answered | Output | |---|---|---| | Proposal | "What authority is being requested?" | Candidate authority description | | Approval | "What authority was actually approved?" | Durable Approved Mission record | | Compilation | "What can enforcement points evaluate mechanically?" | Mission Authority Model | | Projection | "What does this boundary need to know?" | Minimal token, introspection, assertion, or audit view | The AS should remain authoritative for the Approved Mission and the Mission Authority Model forms that govern OAuth processing, even if proposal authoring and compilation are delegated to adjacent services. ### Concrete Compiled Authority Example To make the compilation concept concrete, consider how the scheduling example compiles from proposal inputs into a machine-evaluable authority region. Authoring-time inputs: - intent envelope: `schedule_meeting` for participant Dana, next week - template: `schedule_meeting` with default constraints - approval attenuation: limit to EU region, no executive calendars, max 15 minutes duration The AS-internal Mission Authority Model record (uses `mission_id`; enforcement points receive the signed JWS artifact below, which uses `mission_ref` in place of `mission_id`): ```json { "mission_id": "m_92f341aa", "purpose": "urn:example.com:mission:schedule-meeting", "authority_model": { "allowed_resources": [ { "type": "calendar.event", "selector": "user-manageable-calendars" }, { "type": "crm.account_note", "selector": "accounts-owned-by-requesting-team" } ], "allowed_operations": [ { "group": "calendar.schedule" }, { "group": "crm.record_activity" } ], "constraints": [ { "type": "jurisdiction", "value": "EU" }, { "type": "business_process", "value": "meeting-coordination" }, { "type": "exclusion", "resource_attribute": "calendar.is_executive", "value": true } ], "delegation": { "allowed": true, "max_depth": 0 }, "lifecycle": { "expires_at": 1773069300, "state": "active" } } } ``` The signed JWS artifact distributed to enforcement points (PDP evaluation inputs, gateways, mission-aware RSes). `mission_id` is replaced by `mission_ref`; `expires_at` uses NumericDate per JWT conventions (RFC 7519 Section 2); `version` enables cache invalidation: ```json { "mission_ref": "mr_7M9Qx2", "version": 1, "purpose": "urn:example.com:mission:schedule-meeting", "authority_model": { "allowed_resources": [ { "type": "calendar.event", "selector": "user-manageable-calendars" }, { "type": "crm.account_note", "selector": "accounts-owned-by-requesting-team" } ], "allowed_operations": [ { "group": "calendar.schedule" }, { "group": "crm.record_activity" } ], "constraints": [ { "type": "jurisdiction", "value": "EU" }, { "type": "business_process", "value": "meeting-coordination" }, { "type": "exclusion", "resource_attribute": "calendar.is_executive", "value": true } ], "delegation": { "allowed": true, "max_depth": 0 }, "lifecycle": { "expires_at": 1773069300, "state": "active" } } } ``` This authority-model form is what the AS evaluates at token exchange time, what a gateway queries at request time, and what an AuthZEN-compatible policy decision point (PDP) uses to answer "is this action on this resource permitted under this mission right now?" The agent does not need to re-enumerate its intended actions; the authority model is the evaluable boundary for whatever the agent discovers at runtime. The scheduling scenario's `mission_id` (`m_92f341aa`) maps to protocol-facing `mission_ref` (`mr_7M9Qx2`); this separation illustrates the AS-internal/protocol-boundary distinction normatively defined in the Mission Identifier and Mission Reference section. ## Architecture Layers This architecture is intentionally broader than a single OAuth extension. It is easier to reason about if split into layers. | Layer | Scope | Likely Standardization Target | Representative Capabilities | |---|---|---|---| | **Layer 1: Core OAuth Extension Candidate** | Protocol elements most plausibly standardized as the core OAuth contribution | Core OAuth draft/profile | Mission reference in OAuth requests; Mission-bound token semantics; lifecycle enforcement during issuance, refresh, and exchange; delegation bounds in token derivation; resource server processing expectations; sender-constraining requirements | | **Layer 2: Mission Management Candidate** | Control plane that creates and governs Mission state | Separate management specification or profile | prompt-to-intent interpretation; Mission proposal generation; approval and attenuation; retrieval and management APIs; Mission templates and approval modes; approval UX; enterprise approval integration | | **Layer 3: Cross-Domain and Operational Profiles** | Optional or deployment-specific capabilities | Companion profiles and deployment guidance | Mission assertions across authorization domains; SSF/CAEP eventing; policy integration; gateway and service mesh enforcement; business-event-driven Mission termination | The point of this document is to show how the whole system works end to end. It is not a claim that every layer belongs in one standards-track document. ## Candidate Spec Decomposition This architecture should not be treated as a single protocol surface. The likely standards decomposition is: - a **core OAuth extension** for Mission reference, lifecycle-aware issuance, and exchange - a **mission management specification or profile** for proposals, approval, attenuation, and retrieval - a **cross-domain profile** for mission assertions and trust between authorization domains - **deployment guidance** for gateways, RS behavior, policy integration, and eventing This split matters because the end-to-end architecture is broader than what should probably go into a single OAuth specification. It is also worth being explicit about the architectural choice this series is making. The protocol-facing model here places the Mission at the AS because the goal is to show how Mission governance could fit existing OAuth infrastructure. That is not the only viable system boundary. The deeper governance concept can also be implemented as a separate authority service that the AS consumes. The earlier Power of Attorney series leaned harder in that direction. This document chooses the AS-centered shape because it is the most direct way to make the OAuth implications concrete. ## Design Principle Agents may interpret prompts, but they do **not** grant authority. Authority exists only after a Mission has been proposed, reviewed, and approved. This separation is central to the architecture: - prompt interpretation is probabilistic - authority grant is governed - mission approval is the trust boundary between the two ## End-to-End Flow The intended flow is: ```text prompt -> intent interpretation -> mission proposal -> approval / attenuation -> mission created -> OAuth authorization referencing mission_ref -> access token issuance -> token exchange for downstream APIs ``` Viewed by trust boundary, the same path looks like: ```text [agent / client] | | prompt, plan, MCP context v [mission management] | | proposal, approval, attenuation v [authorization server] | | mission-bound token | mission-aware token exchange v [gateway / resource servers] | | resource operations, audit, policy checks v [mission lifecycle state] active -> suspended / completed / revoked / expired ``` This makes the Mission the stable authority artifact across otherwise separate OAuth transactions. An end-to-end deployment may therefore involve three linked phases: 1. **Interpretation phase**: prompts or plans become structured candidate authority 2. **Governance phase**: candidate authority is approved, attenuated, or denied 3. **OAuth execution phase**: approved Mission state is referenced by tokens and enforced over time This should not be confused with ordinary repeated access checks. Continuous authority evaluation is a separate control-plane question: not only whether the next request is permitted, but whether the Mission behind the execution should still be running at all as facts, approvals, and business conditions change over time. The enforcement picture across those phases looks like this: | Check / Control | Proposal / approval | Code issuance | Token issuance / refresh | Token exchange | Gateway / RS | Cross-domain projection | |---|---|---|---|---|---|---| | Mission lifecycle state | Created or denied | Checked | Checked | Checked | Often checked via introspection or cached state | Reflected at issuance time only unless live state is shared | | Mission Authority Model bounds | Compiled | Bound to resulting flow | Enforced | Enforced | Enforced directly or via policy inputs | Reduced to projected facts | | Delegation depth | Declared | N/A | N/A | Enforced atomically | Usually observed, not advanced | Visible only as projected chain state | | Verified actor binding | Approved actor context anchored | Bound to code / initial flow | Bound to issued token | Re-verified | Usually indirect unless Mission-aware | Degrades to projection unless introspection is available | | Business-event termination | Declared as terminal condition | N/A | Checked against current state | Checked against current state | Propagated through introspection / eventing | Stale unless the receiving domain has live state | ## Relationship and External Data Sources The architecture now relies on relationship predicates such as: - accounts owned by the requesting team - participants connected to the approved Mission - calendars the subject is allowed to manage - records in a specific business process stage Those predicates depend on external systems of record. Mission evaluation may therefore depend on one or more relationship sources: - directory or identity graph - FGA or graph authorization system - CRM ownership model - business-process state system - HR hierarchy - tenant or organization membership directory Mission-Bound OAuth does not replace those systems. It carries the governing Mission context that tells the PDP which relationship predicates matter for the current Mission. # Mission Data Model ## Mission Object The current model treats a Mission as a persistent authorization context. For interoperability, the eventual spec work should distinguish a **minimal core** from **deployment-specific extensions**. The minimal interoperable core is roughly: - `mission_id` - `mission_state` - `mission_subject` (required sub-fields: `sub`, `iss`; strongly recommended: `sub_profile`) - `mission_client` - `created_at` - `mission_exp` - `delegation` Deployment-specific extensions may include: - `purpose` - structured `constraints` - compiled authority graph or selector set - enterprise approval metadata - mission-specific attributes - policy evaluation hints A sketch of the object shape: ```json { "mission_id": "m_7M9Qx2", "mission_state": "active", "mission_subject": { "sub": "user-123", "iss": "https://idp.example.com", "sub_profile": "user" }, "mission_client": { "client_id": "assistant-agent" }, "mission_exp": 1773072000, "delegation": { "allowed": true, "max_depth": 1, "current_depth": 0 }, "purpose": { "class": "urn:example.com:mission:schedule-meeting", "display": "Schedule a Meeting" }, "authority_model": { "operation_groups": [ "calendar.schedule", "crm.record_activity" ], "selectors": [ { "resource_type": "calendar.event", "selector": "user-manageable-calendars" }, { "resource_type": "crm.account_note", "selector": "accounts-owned-by-requesting-team" } ], "predicates": [ { "type": "jurisdiction", "value": "EU" }, { "type": "business_process", "value": "meeting-followup" }, { "type": "exclusion", "resource_attribute": "calendar.is_executive", "value": true } ] }, "constraints": { "max_duration": 900, "rate_limit": { "count": 10, "window": 60 }, "checkpoint_policy": "hybrid" }, "created_at": "2026-03-13T09:00:00Z" } ``` This example is AS-internal. `mission_exp` uses NumericDate format (integer seconds since Unix epoch) consistent with the JWT `exp` claim convention defined in RFC 7519 Section 4.1.4. `created_at` remains an internal timestamp field here. Protocol projections should use the explicit field formats defined for the relevant projection rather than assuming this internal object shape is emitted directly. The AS owns this record. Tokens and exchanges are derivatives of it, not substitutes for it. The proposal and the Mission are separate artifacts. A Mission Proposal is the requested authority object submitted for review. Approval creates an Approved Mission artifact with its own `mission_id`, lifecycle, authority model, and audit trail. This matters for the API surface and for governance: - `GET /mission-proposals/{proposal_id}` returns the requested authority object and its review state - `GET /missions/{mission_ref}` returns the approved authority artifact that governs OAuth processing - denial and attenuation history belong to the proposal record even when no Mission is ever created At minimum, `mission_id` should be opaque and unguessable. If exposed outside the AS, it should be treated as a reference handle, not as a container for semantics. ## Mission Identifier and Mission Reference The architecture is cleaner if it distinguishes the AS-internal Mission identifier from the protocol-facing Mission reference. - **`mission_id`**: the authoritative identifier of the Mission record inside the issuing AS - **`mission_ref`**: the projected reference handle used at protocol boundaries such as tokens, token exchange, introspection, and cross-domain assertions In the simplest deployment, `mission_ref` may be a direct opaque projection derived from `mission_id`. In privacy-sensitive or cross-domain deployments, it often should be pairwise or otherwise distinct per boundary. That distinction separates three concerns that would otherwise get overloaded into one value: - record identity at the AS - protocol selection during token exchange and introspection - correlation visibility at resource servers or other external parties The practical model is: - the AS stores and governs the Mission by `mission_id` - clients and downstream systems work with `mission_ref` - the AS maps `mission_ref` back to the internal `mission_id` This is the recommended direction for the eventual specs. The core protocol should standardize the existence of a projected Mission reference. Whether the claim name remains `mission_id`, becomes `mission_ref`, or is profile-dependent can still be decided later. This distinction is normative. The `mission_id` MUST NOT appear in tokens, authorization requests, introspection requests or responses, cross-domain assertions, or error responses. It MUST NOT appear in any artifact distributed outside the AS boundary, including the signed Mission Authority Model JWS artifact that enforcement points receive (which MUST use `mission_ref` in place of `mission_id`). All protocol-facing and enforcement-point-facing uses MUST use `mission_ref`. The only contexts where `mission_id` may appear are: (1) AS-internal data stores and records, and (2) examples in this document that explicitly label the content as AS-internal representation. For open-world deployments, the important part of the Mission may not be a static list of resources or operations. It may be the compiled set of selectors, predicates, relationship conditions, and policy bindings that define the bounded authority region for runtime decisions. > A Mission is not just a record of approved intent; it is the authoritative Mission Authority Model for a delegated mission. ## Mission Authority Model as a Stored, Versioned Artifact The Mission Authority Model is a stored, content-addressed artifact maintained by the AS. It is not recomputed on demand at each evaluation point. This is a deliberate architectural decision driven by audit and enforcement requirements. The audit trail depends on replayability: the AS must be able to reconstruct exactly what authority governed any given token issuance or exchange decision. That requires a stored, versioned representation of the compiled authority at the moment of issuance. A computed-on-demand model cannot provide that guarantee because the inputs to compilation (templates, policy, registered predicates) may change between the time of issuance and the time of audit replay. The AS always stores the Mission Authority Model for audit and issuance purposes. Distribution of that full model beyond the AS is optional and should be treated as a higher-assurance profile rather than the default deployment expectation. In the default adoption path: - the AS uses the Mission Authority Model internally for issuance, refresh, exchange, and lifecycle checks - gateways and RSes use projected claims or the Mission introspection profile - only designated high-trust enforcement points retrieve the full signed Mission Authority Model High-assurance deployments may distribute the Mission Authority Model to trusted enforcement points rather than computing it locally: - the AS issues the Mission Authority Model as a signed artifact alongside the Approved Mission - enforcement points (gateways, PDPs, resource servers that do full Mission evaluation) retrieve or receive the Mission Authority Model and validate its signature - cache staleness bounds for the Mission Authority Model at enforcement points must be policy-defined; enforcement points must re-fetch when staleness bounds are exceeded or when a revision event arrives via SSF/CAEP When a Mission is amended or re-compiled (for example, when the AS updates a predicate in response to a business-graph change), the AS increments a version counter and issues a new signed Mission Authority Model. Enforcement points that cached a prior version must treat a version mismatch as a cache miss and re-fetch. This is the mechanism that keeps distributed enforcement consistent with the AS's authoritative record. **Cache coordination between Mission Authority Model and introspection**: enforcement points maintain two separate caches: the signed Mission Authority Model artifact and the RFC 7662 introspection response. These must be treated as coherent: a Mission Authority Model version mismatch (detected by comparing the `version` field in a newly fetched artifact against the cached version) MUST be treated as equivalent to an introspection cache miss, triggering a fresh introspection call before any further enforcement decision. The recommended ordering on version mismatch: (1) re-fetch Mission Authority Model, (2) re-introspect to confirm `active: true` and obtain current `mission_state`, (3) enforce against the updated artifact. An enforcement point MUST NOT apply a new Mission Authority Model version while holding a stale introspection `active: true` response from before the version increment. > The Mission Authority Model is an artifact the AS signs and enforcement points obtain, not a function enforcement points compute locally. **Mission Authority Model retrieval endpoint**: in deployments that use distributed authority-model enforcement, enforcement points that need to obtain or refresh the Mission Authority Model do so via a dedicated endpoint at the AS. The endpoint pattern is: ```text GET /missions/{mission_ref}/authority-model Authorization: Bearer ``` The AS returns the signed JWS artifact. The `enforcement_credential` is a client credentials access token with scope `mission:authority-model:read`, issued to the enforcement point's registered client identity. Enforcement points cache the artifact using standard HTTP caching semantics; the AS MUST include appropriate `Cache-Control` headers. The AS also pushes revision notifications via SSF when the Mission Authority Model version increments, allowing enforcement points to proactively re-fetch. An enforcement point that cannot reach the retrieval endpoint MUST fail closed: it MUST treat the Mission as if it were `revoked` until it can retrieve a fresh artifact. **Signing format**: the Mission Authority Model is signed as a JWS (RFC 7515) JSON object using the AS's token signing keys. The signing keys are discoverable via AS metadata (RFC 8414) under the `jwks_uri` field. The signed artifact MUST include the following JOSE header claims: - `typ`: `"mission+json"` (a new media type candidate for registration) - `alg`: the same algorithm family used for the AS's access token signing (e.g., `RS256`, `ES256`) - `kid`: key identifier for signature validation The payload is the Mission Authority Model JSON object including `mission_ref`, `version`, `authority_model`, `lifecycle`, and `delegation` fields. Trusted internal enforcement points MAY maintain a local mapping from `mission_ref` to the AS-internal `mission_id`, but the distributed artifact itself uses only `mission_ref` at its protocol boundary. Enforcement points validate the JWS signature against the AS's published `jwks_uri` before consuming any Mission Authority Model data. A Mission Authority Model with an invalid or unverifiable signature MUST be rejected and treated as if the Mission were revoked. ## Authority Model Distribution The architecture needs a clear trust boundary for who is allowed to receive the full Mission Authority Model versus a filtered projection. The recommended distribution model is: | Caller Class | Allowed View | Typical Use | |---|---|---| | **Authorization Server** | Full Mission record and full Mission Authority Model | authoritative issuance, exchange, lifecycle, audit | | **PDP acting for the AS or gateway** | Full Mission Authority Model or a minimally filtered evaluation view | runtime policy evaluation | | **Gateway** | Full Mission Authority Model only when it is a designated enforcement point | high-value request enforcement, distributed checkpointing | | **Mission-aware RS** | Filtered introspection view by default; full model only in high-assurance profiles | request-time authorization decisions | | **Baseline RS** | Projected Mission reference only | audit and correlation | | **Cross-domain AS** | Projected Mission assertion only | local re-evaluation and local token issuance | The default should be conservative: - full Mission Authority Model distribution is for trusted enforcement points, not every resource server - filtered introspection is the default RS-facing mechanism - projected token claims are the minimum distribution mechanism This is the default trust pattern for the architecture: trusted enforcement points may receive the full Mission Authority Model; resource servers default to filtered introspection or token-level projections. This keeps the architecture aligned with its own privacy model. A deployment that distributes the full Mission Authority Model broadly should be treated as a high-assurance or tightly trusted profile, not as the default interoperability expectation. ## Stable vs Dynamic Evaluation One boundary worth making explicit is which parts of Mission evaluation are stable versus dynamic. | Category | Examples | Changes How? | |---|---|---| | **Stable Mission data** (persisted in Approved Mission and Mission Authority Model) | mission identity, purpose, delegation bounds, compiled selectors, operation groups, compliance predicates, expiry, checkpoint policy | Only via amendment or revocation + re-issuance; each change produces a new versioned Mission Authority Model | | **Mission lifecycle state** (durable AS-maintained state) | `active`, `suspended`, `completed`, `revoked`, `expired` | Transitions over time; affects all downstream decisions without re-authoring the Mission (`pending` is a proposal lifecycle concept, not a Mission state) | | **Dynamic evaluation inputs** (supplied at runtime) | current resource instance, current actor, current mission stage, current region, current business relationship state, external policy state | Change without modifying the Mission; evaluated at each decision point | The reason this distinction matters is that not every denial means the Mission changed. A request may be denied because the runtime facts no longer satisfy the predicates of an otherwise unchanged Mission Authority Model. ## Resource and Action Model Simple string scopes are too weak for the authority model this architecture requires. The current direction is to use typed resources and actions. Example: ```json { "resource": { "type": "calendar", "id": "primary" }, "action": { "name": "create_event", "group": "write" } } ``` This helps with: - container-scoped operations - action grouping - object-level permissions - extensibility over time - compatibility with structured policy systems This also aligns better with modern policy engines than raw space-delimited scopes. The likely protocol consequence is that a core spec should standardize only enough structure to make policy evaluation interoperable, while leaving detailed resource taxonomies to deployment profiles. ## Scaling the Resource and Operation Model This becomes much more important in real systems than it first appears. Real deployments do not have one API and one action. They have: - containers and objects - object hierarchies - bulk operations - derived operations - tenant boundaries - environment-specific identifiers - operation families that map poorly to raw OAuth scopes A usable architecture therefore needs a model that can scale beyond flat strings such as `calendar.write`. The likely shape is: - **resource type**: what kind of thing is being acted on - **resource instance or selector**: which thing or set of things is in scope - **action name**: the concrete operation - **action group**: a stable grouping used by policy and approval UX - **attributes**: optional properties used for finer evaluation A sketch: ```json { "resource": { "type": "calendar.event", "container": { "type": "calendar", "id": "primary" }, "selector": { "owner": "user-123", "time_range": "2026-03-13/2026-03-20" } }, "action": { "name": "create", "group": "write" } } ``` The point is not to standardize every domain taxonomy. The point is to give Mission-Bound OAuth and related policy systems enough structure to express container-scoped authority, object-level authority, grouped approvals, and policy evaluation on typed entities. ## Resource Selectors as an Abstraction The architecture likely needs the equivalent of XPath, CSS selectors, or jQuery selectors for resources, but not as a single universal syntax. What it needs is a **resource selector abstraction**: a standard place in the Mission model to describe "which resources or resource sets are in scope" without forcing every deployment into one selector language. In practice, selectors may need to express things like: - calendars the subject can manage - CRM accounts owned by the current team - documents in a folder but not under legal hold - records in a given jurisdiction - tickets connected to a specific business process stage Those are not all the same kind of selection. Some are: - attribute filters - relationship predicates - container-scoped selectors - policy references - graph traversals The architecture should therefore treat selectors as an abstraction with multiple possible forms, for example: ```json { "resource_type": "crm.account_note", "selector": { "kind": "relationship", "relation": "accounts-owned-by-requesting-team" } } ``` ```json { "resource_type": "calendar.event", "selector": { "kind": "attribute_filter", "where": { "calendar.owner": "user-123", "calendar.region": "EU" } } } ``` ```json { "resource_type": "document", "selector": { "kind": "policy_ref", "ref": "policy://missions/docs/editable-by-subject-team" } } ``` This keeps the model flexible enough for AuthZEN, Cedar, Rego, FGA, and deployment-specific policy systems without prematurely standardizing a single resource query language. The important standardization boundary is not the selector syntax. It is the existence of a selector slot in the Mission model and the expectation that Mission Authority Models may carry resource selectors, not just literal resource IDs or flat allowlists. ## Key Abstraction Slots Resource selectors are not the only place where the architecture needs a stable slot without prematurely standardizing a full language. Several parts of the Mission model have the same shape: - the architecture needs a place to carry meaning - deployments will want different underlying syntaxes or policy engines - the first spec should standardize the slot and its role before trying to standardize every semantic language The main abstraction slots are: | Abstraction Slot | What It Expresses | Likely Backing Models | |---|---|---| | **resource selectors** | which resources or resource sets are in scope | attribute filters, relationship predicates, policy refs, graph selectors | | **operation groups** | stable approval and policy groupings for actions | deployment taxonomies, API-specific action families | | **relationship predicates** | subject/resource or actor/resource relationships that affect authority | FGA graphs, directories, CRM ownership models, HR hierarchies | | **process-state predicates** | business workflow or case state that gates authority | BPM systems, ticketing state, CRM stage, case lifecycle | | **compliance constraints** | jurisdiction, residency, legal, or regulatory boundaries | policy engines, data classification systems, residency controls | | **authority envelopes** | the bounded region inside which open-world expansion is allowed | Mission Authority Model, policy bindings, approval attenuations | | **terminal conditions** | which events or states suspend, complete, or revoke a Mission | SSF/CAEP events, business system events, local lifecycle rules | | **checkpoint policies** | when synchronous checks are required versus when signal-based continuity is acceptable | risk policies, action classes, operational profiles | | **projection policies** | what Mission data may be exposed in tokens, introspection, assertions, or audit | privacy rules, audience filtering, trust-domain rules | | **explanation reasons** | machine-readable and human-readable reasons for denial, attenuation, suspension, or revocation | policy reason codes, audit schemas, admin UX models | This is an important discipline for the eventual specs. If Mission-Bound OAuth tries to standardize all of these semantic languages in one step, it will become too broad to be practical. If it names none of them, deployments will fill the gaps with incompatible private conventions. The practical middle ground is: - standardize the slots and processing checkpoints first - standardize only the smallest common structures needed for interoperability - leave richer selector, predicate, and explanation languages to profiles or adjacent specifications # Mission Lifecycle ## Proposal Lifecycle vs Mission Lifecycle The Mission Proposal and the Mission are separate artifacts with separate lifecycles. The Mission Proposal lifecycle governs what happens before an authorized Mission exists: ```text +---------+ | pending |<-- proposal submitted +----+----+ | +---------+---------+ | | approve deny / timeout | | v v +---------+ +----------+ +----------+ | Mission | | denied | | expired | | created | +----------+ +----------+ +---------+ (terminal) (terminal) ``` `denied` is the terminal state when a proposal is explicitly rejected by the approver. `expired` is the terminal state when the proposal approval window elapses without a decision. Both are terminal on the proposal object. Neither creates a Mission. Denial and timeout history are retained on the proposal record for audit even when no Mission is ever created. The Mission lifecycle begins at activation and is independent of the proposal lifecycle: ## Mission Lifecycle The current lifecycle model is: ```text task done / client signals / business event +--------+ | +---------->| active |-----+-------> completed | +---+----+ resume | | suspend / anomaly / precondition change | | | v | +-----------+ +---------| suspended| +-----+-----+ | revoke / expire | +------------+------------+ | | v v +---------+ +---------+ | revoked | | expired | +---------+ +---------+ ``` Missions are created in `active` state when a proposal is approved. For policy-auto-approved missions, activation is immediate. There is no Mission-level `pending` state; pending is a proposal lifecycle concept. Valid terminal states are `completed`, `revoked`, and `expired`. `suspended` is not terminal: it requires an explicit resumption event to return to `active`, or a revocation or expiry event to terminate. In the architecture, lifecycle enforcement applies before: - authorization code issuance - access token issuance - refresh token use - token exchange - delegation events The important property is that mission authority can be suspended or terminated independently of token possession. **Terminal state invariant**: The states `completed`, `revoked`, and `expired` are terminal. An AS MUST NOT accept any lifecycle transition request targeting a Mission in a terminal state. A `completed` or `revoked` Mission cannot be resumed, re-activated, or amended. **`completed` vs `revoked` semantics**: both states block all further token issuance, refresh, and exchange. The behavioral difference is in the error code returned and in audit interpretation. `mission_completed` is returned when the Mission ended normally (purpose achieved or business event signaled completion). `mission_revoked` is returned when the Mission was terminated by an authorized party before purpose was achieved or due to policy enforcement. Clients receiving `mission_completed` know the mission succeeded; clients receiving `mission_revoked` know it was externally terminated. Both require a new Mission for any further execution. ## Lifecycle Ownership Mission lifecycle transitions are IAM governance actions and should not be left implicit. The transition model should distinguish who is allowed to perform which action: - **proposal submitter / client**: may request creation and may signal completion when permitted by policy - **subject**: may approve, deny, or revoke Missions that are acting on their behalf when policy allows - **administrator**: may approve, attenuate, suspend, resume, revoke, or terminate Missions within administrative scope - **policy engine**: may auto-approve, suspend, or revoke according to registered rules - **business event processor**: may transition a Mission to `completed` or `revoked` when declared terminal conditions are met At a minimum, the architecture should assume: - creation authority does not imply approval authority - execution authority does not imply expansion authority - suspension and revocation are privileged lifecycle actions - business-event termination is authorized only when the Mission declared that event source as authoritative **Suspended state** deserves explicit treatment. Suspension is not revocation. It is a temporary hold on execution, typically triggered when a human review is required mid-mission, an anomaly is detected, or a precondition the mission depended on changes. When a mission is suspended: - token exchange is denied until the mission returns to active - in-flight requests that have already received tokens run to their token expiry unless active invalidation is applied - the agent should receive a structured error from the exchange endpoint indicating the suspension, not a generic rejection - resumption is authorized by the same class of principals that can approve the original Mission: the subject (for user-delegated Missions), an administrator within scope, or a policy engine that declared the suspension condition resolved - the resumption API follows the same endpoint pattern as approval: `POST /mission-proposals/{proposal_id}/approval` for pending Missions maps to a `POST /missions/{mission_ref}/resume` for suspended Missions, requiring the same authentication and authorization as the original approval action - the AS re-evaluates the Compiled Mission's validity at resumption time; if conditions have materially changed during suspension (for example, a key policy predicate is no longer satisfiable), the AS MAY decline resumption and transition to `revoked` instead - the AS MUST emit a `mission.resumed` audit event on successful resumption - **Maximum suspension duration**: a suspended Mission MUST NOT remain suspended indefinitely. The AS MUST enforce a maximum suspension window that is either: (a) declared in the Mission Authority Model at approval time (`max_suspension_seconds`), or (b) a deployment-default suspension limit defined in AS policy. When the maximum suspension window elapses without a resumption event, the AS MUST automatically transition the Mission to `revoked` and MUST emit a `mission.revoked` audit event with reason `suspension_timeout`. Deployments MUST configure an explicit maximum suspension window. An unbounded suspension window is not permitted, as it produces orphaned authority objects with indeterminate audit trails. Suspension is the primary mechanism for human-in-the-loop intervention after execution has started. Its behavior, error codes, and resumption flow should be normatively defined in the core spec rather than left to implementation. **Business event termination** is the mechanism that closes the gap the series identified. The CFO scenario (agent still pulling financials at 2:05 PM, five minutes after the board approved the presentation) fails because business completion events do not flow into the authority layer. Mission-Bound OAuth addresses this by making business events first-class inputs to Mission lifecycle transitions. A Mission may define terminal conditions tied to business events: a procurement program is cancelled, a renewal conversation closes, a task is marked complete in a ticketing system. When those events fire, the Mission transitions to `completed` or `revoked` regardless of how much time remains on the clock. The mechanism for delivering those events is SSF/CAEP, described in the operational model section. This is the architecture's continuous authority evaluation loop: authority is re-evaluated not only at issuance and exchange time, but also when external events change whether the Mission should continue at all. The point is not only to stop future token issuance, but to give enforcement points enough signal to halt execution that is no longer authorized to continue. **Business event integrity and ordering** must also be treated as part of the lifecycle model, not as an implementation afterthought. Event-driven termination is only trustworthy if the AS can distinguish authoritative events from stale, duplicated, replayed, or out-of-order ones. A duplicated `task.completed` event should be idempotent; a delayed `task.reopened` event arriving after revocation should not silently reactivate a terminal Mission; an event from an unregistered source should have no lifecycle effect at all. The architectural expectations are: - each terminal condition is bound to one or more registered event sources the Mission declared as authoritative at approval time - lifecycle events are processed idempotently using event identifiers or equivalent replay-detection state at the AS - the AS records event time and processing time separately so out-of-order delivery is visible in audit - terminal lifecycle transitions remain terminal even if a later event would otherwise imply an earlier state - deployments that cannot establish event authenticity and replay protection for a given source SHOULD NOT allow that source to drive Mission termination directly This is the same trust boundary discipline applied elsewhere in the architecture: external systems may supply lifecycle-driving facts, but the AS remains authoritative for how those facts are validated and turned into Mission state transitions. **Refresh token and in-flight token behavior** must be addressed explicitly. Refresh tokens issued under a Mission are derivatives of that Mission, not independent credentials. The AS MUST record the `mission_id` associated with any refresh token at the time of issuance. This association is an AS-internal record and MUST NOT rely on the client to supply it at refresh time. When a Mission transitions to `revoked`, `suspended`, or any terminal state, the AS MUST immediately invalidate all refresh tokens associated with that `mission_id` using RFC 7009 token revocation semantics. This applies regardless of the refresh token's remaining lifetime. Allowing a client to exchange a Mission-linked refresh token for a new access token after Mission revocation defeats the lifecycle guarantee the architecture is designed to provide. For already-issued short-lived access tokens still in the client's possession when a Mission terminates, the architecture cannot retroactively invalidate bearer tokens without active revocation infrastructure. The recommended approach is twofold: keep access token lifetimes short to minimize the exposure window, and emit a CAEP termination event to enforcement point subscribers who can block the token at a gateway or policy enforcement layer. Deployments that require immediate invalidation for all in-flight tokens should use DPoP or mTLS so a stolen or post-revocation token cannot be used without the bound key. **Mission lifecycle error codes** must be normatively defined in the core spec. When token exchange or refresh fails due to Mission state, the AS should return a structured error that allows the agent to take a meaningful action rather than treating all rejections identically. | Error Code | Condition | Agent Behavior | |---|---|---| | `mission_suspended` | Mission is temporarily held | Halt execution; await resumption signal before retrying | | `mission_revoked` | Mission permanently terminated | Stop execution; a new Mission is required | | `mission_completed` | Mission reached its intended terminal state normally | Execution is complete; no further action required | | `mission_expired` | Mission lifetime elapsed | Stop execution; a new Mission is required | | `mission_delegation_depth_exceeded` | Requested delegation would exceed `max_depth` | Reject delegation request; escalate or abort | | `mission_authority_exceeded` | Requested resource or action outside compiled authority region | Abort this action; do not retry with same Mission | | `mission_not_found` | No Mission matching the provided `mission_ref` | Verify `mission_ref` or request a new Mission | | `mission_ref_required` | Multiple active Missions exist for this client and no `mission_ref` was provided in `authorization_details` | Include the correct `mission_ref` in `authorization_details` and resubmit | | `mission_expansion_conflict` | An expansion proposal was evaluated against a prior Mission version; a concurrent expansion was already accepted | Re-fetch the current Mission state and re-evaluate the expansion against the updated version before resubmitting | These values appear in the `error` parameter of the token error response per RFC 6749 Section 5.2, with a `mission_ref` field in the error response body echoing back the projected Mission reference the client passed. The error response uses `mission_ref`, not the AS-internal `mission_id`, because the client has no visibility into the internal identifier. The distinction between `mission_suspended` (temporary, agent waits) and `mission_revoked` (permanent, agent stops) is operationally critical and must not be collapsed into a single error code. **Structured error detail for `mission_authority_exceeded`**: this error code alone is insufficient for client recovery because the agent cannot determine which constraint check failed without additional information. When returning `mission_authority_exceeded`, the AS SHOULD include a `mission_error_detail` object in the error response body: ```json { "error": "mission_authority_exceeded", "mission_ref": "mr_7M9Qx2", "mission_error_detail": { "constraint_violated": "resource_type", "detail": "resource type 'finance.report' is not in the compiled authority region" } } ``` The `constraint_violated` field uses one of the following machine-readable values: - `resource_type`: the requested resource type is outside the compiled authority - `operation_group`: the requested operation is outside the compiled authority - `relationship_predicate`: a relationship constraint failed (e.g., the account is not owned by the requesting team) - `compliance_constraint`: a compliance or jurisdiction constraint failed - `lifecycle_constraint`: a lifecycle-based authority condition in the compiled authority region failed (e.g., the business process stage is not in the approved set, or a time-window constraint in the compiled authority has elapsed). This value is ONLY used within `mission_error_detail` for `mission_authority_exceeded` responses. It does not overlap with the Mission lifecycle state error codes (`mission_suspended`, `mission_revoked`, `mission_expired`) which are returned as top-level `error` values, not as `constraint_violated` values. The `detail` field is a human-readable diagnostic string intended for logging, administrative display, and debugging. It MUST NOT be machine-parsed; its format is not normative and may change between AS versions. Clients MUST NOT implement logic that branches on the content of the `detail` field. The AS SHOULD provide the `detail` string in the language indicated by the request's `Accept-Language` header when that header is present. Only `constraint_violated` is the machine-readable discrimination signal; `detail` is explanatory context for human operators. These values allow the agent to determine whether to abort, request a Mission expansion, or attempt a different resource. ## Revocation Semantics Across Derivatives Mission revocation has to be stronger than "stop issuing new tokens." Three derivative classes matter operationally: - **refreshable credentials**: refresh tokens and equivalent long-lived token derivation handles - **new exchanges**: token exchange requests for new audiences or delegation hops - **already-issued short-lived access tokens**: existing audience-bound tokens still in circulation The expected behavior is: - Mission revocation or suspension immediately blocks refresh and exchange - associated refresh tokens are revoked or made unusable - already-issued short-lived access tokens remain usable only until expiry unless active invalidation infrastructure blocks them earlier - high-assurance deployments use sender-constraining plus gateway or event-driven invalidation to reduce the post-revocation exposure window This makes the lifecycle story operationally honest: Mission governance is authoritative, but immediate stop across all already-issued tokens still depends on the enforcement profile. **Mission amendment and narrowing** are distinct from expansion and require an explicit position. The architecture currently defines expansion (adding within existing bounds) as a first-class operation via expansion proposals. The inverse, narrowing an active Mission's authority region, shortening its expiry, or reducing delegation depth, is not yet defined. The two candidate models are: (1) a formal Mission amendment endpoint where authorized principals can tighten constraints on an active Mission without revocation; (2) revocation and re-issuance as the only path for any structural change. The revocation + re-issuance model avoids consistency problems between the AS's Mission record and any cached compiled authority at enforcement points. The amendment model is operationally more convenient for long-running Missions. This is an open design question for feedback. **OIDC session lifecycle and Mission lifecycle**: for user-delegated Missions, when a user's OIDC session is revoked (CAEP `session_revoked` event, logout, or device credential revocation), active Missions for that user should be affected. The natural default is suspension: all active user-delegated Missions for the revoked session are suspended, giving the orchestration layer an opportunity to cleanly unwind in-flight execution before the Missions are terminated. Deployments with stricter requirements may choose immediate revocation. Regardless, the session-to-Mission propagation behavior should be defined explicitly per deployment profile rather than left to AS-specific behavior. ## Concurrent Missions The architecture assumes concurrent active Missions are permitted. A client may hold multiple active Missions for the same user simultaneously, each representing a distinct delegated workflow running in parallel. Concurrent Missions reflect how real agentic deployments work: an assistant agent may be executing a "schedule meeting" workflow while simultaneously running a "prepare expense report" workflow for the same user. Requiring the first to complete before the second can be authorized would unnecessarily serialize independent workflows and force agents to queue tasks rather than interleave them. The security goal is to avoid implicit Mission selection while also reducing how much fragile bookkeeping the client must do. The preferred runtime model is: - each primary mission-bound orchestration token is bound to exactly one `mission_ref` - the orchestration layer keeps one in-flight mission-bound token per active Mission - token exchange requests either echo that `mission_ref` explicitly or omit it when the subject token is already uniquely bound to one Mission The AS does not infer Mission context from the requested resource. It infers only from the subject token when that token is already uniquely bound to one Mission. If the client supplies an explicit `mission_ref`, the AS MUST compare it to the subject token's bound Mission reference and reject the request on mismatch. If the subject token does not uniquely identify one Mission and the request omits `mission_ref`, the AS returns `mission_ref_required`. This is the safer adoption model: - the client does not have to maintain a separate out-of-band Mission lookup table for every exchange - the AS remains authoritative for Mission binding - accidental Mission-context swaps become detectable server-side rather than silently becoming application bugs A request that references the wrong Mission for a given resource is rejected with `mission_authority_exceeded` or `invalid_grant`, depending on whether the failure is an authority-envelope violation or a Mission-binding mismatch. ## Mission Audit Trail Every Mission state transition should produce a signed audit event as a first-class artifact: - `mission.created` - `mission.activated` - `mission.delegated` (with delegation target and depth) - `mission.suspended` (with reason) - `mission.resumed` - `mission.expanded` (with prior and updated authority region) - `mission.completed` - `mission.revoked` (with revoking principal and reason) - `mission.expired` This event log is a compliance artifact that is independent of access logs, token rotation cycles, and AS internal state. It survives token rotation cycles that would otherwise erase execution history. Audit events should be signed by the AS and should include both `mission_id` (for AS-internal correlation) and `mission_ref` (for cross-boundary audit correlation), the transition timestamp, the triggering principal, and the triggering event (clock, business event, user action, or policy signal). External auditors and cross-domain audit systems cannot resolve the AS-internal `mission_id`; the `mission_ref` is the portable correlation handle that links audit records across the AS, resource servers, gateways, and downstream domains. Positioning the audit trail as a produced artifact, not just a logged side effect, is what makes delegated execution attributable and reviewable. But audit alone is not enough. Mission governance only becomes real when it lands in execution control. If a Mission is suspended, revoked, or reaches a terminal condition, the surrounding runtime has to know how to pause, unwind, terminate, or escalate before irreversible work continues. A perfect audit trail paired with an orchestrator that keeps running is still a governance failure. # OAuth Protocol Integration ## Worked Example: Scheduling Assistant To make the architecture less abstract, consider a scheduling assistant that can use Calendar, Email, and CRM tools. The user says: > Schedule lunch with Dana next week, send the invite, and log the follow-up in Salesforce. ### Step 0: User authentication For user-delegated missions, the user must be authenticated before a Mission can be created on their behalf. The **auth-first model** is the primary pattern: the user authenticates at the IdP via an OIDC flow, and the resulting authenticated session provides the identity context the orchestration layer uses when submitting the Mission proposal. The proposal carries the authenticated user's subject identifier, and the AS validates that the orchestration layer's `client_id` is registered to propose missions on behalf of that user. The approval step may be separate from authentication (the user approves a pending proposal through an asynchronous consent interaction) or collapsed with it (a combined authenticate-and-approve screen). Either path produces the same outcome: an Approved Mission with a verified `mission_subject`. For headless missions, this step is replaced by client credential authentication at the orchestration layer with no interactive user authentication required. ### Step 1: Tool discovery and planning The agent uses MCP to discover available tools and their schemas: - calendar availability search - calendar event creation - email send - CRM note creation MCP helps the agent understand what actions are possible and what parameters are needed. It does not grant authority to use any of them. ### Step 2: Prompt interpretation and proposal creation The agent interprets the prompt into an Intent Envelope and a candidate Mission Proposal: ```json { "purpose": { "class": "urn:example.com:mission:schedule-meeting", "display": "Schedule Lunch with Dana" }, "template_id": "schedule_meeting", "subject": { "sub": "user-123", "iss": "https://idp.example.com" }, "candidate_authority": { "resource_types": ["calendar.event", "crm.account_note"], "operation_groups": ["calendar.schedule", "crm.record_activity"], "constraints": { "relationship": "accounts-owned-by-requesting-team", "business_process": "meeting-followup", "region": "EU" } }, "parameters": { "participant": "Dana", "time_window": "next week" }, "display": { "title": "Schedule a Meeting", "description": "The assistant will find availability and create a lunch meeting with Dana next week, send the invite, and log a CRM note.", "actions": ["Check calendar availability", "Create calendar event with Dana", "Send email invitation", "Log CRM note"], "constraints": ["EU data only", "Expires in 15 minutes"] } } ``` The proposal is then submitted to the mission-management layer: ```text POST /mission-proposals ``` ### Step 3: Approval and attenuation The AS or associated control-plane service evaluates the proposal. A user, enterprise policy, or administrator may attenuate it before approval. For example, policy might allow: - meeting-related scheduling actions for calendars the user is allowed to manage - invite sending only to participants connected to the approved meeting mission - CRM note creation only for accounts owned by the current team - execution only within a 15-minute mission lifetime - no further delegation beyond the assistant runtime - processing only in approved regional and compliance boundaries The result is an approved Mission record at the AS, which is then projected into protocol-facing flows through a `mission_ref`. ### Step 4: Policy evaluation with AuthZEN At approval time, and again later during token derivation, the AS may act as a Policy Enforcement Point (PEP) and call an AuthZEN-compatible PDP. Conceptually, the question is no longer just "is Calendar on the allowlist?" It is closer to: ```json { "subject": { "type": "client", "id": "assistant-agent" }, "action": { "name": "create_event", "group": "write" }, "resource": { "type": "calendar.event", "container": { "type": "calendar", "id": "primary" } }, "context": { "mission_ref": "mr_7M9Qx2", "purpose": "urn:example.com:mission:schedule-meeting", "mission_state": "active", "relationship": { "participant_in_mission": true }, "business_process": { "type": "meeting-coordination", "stage": "scheduling" }, "compliance": { "region": "EU" } } } ``` Mission-Bound OAuth defines when those checks happen. AuthZEN provides one way to externalize the decision. ### Step 5: OAuth authorization and mission-bound token issuance Once approved, the client starts OAuth authorization referencing the Mission, preferably through `authorization_details`: ```json { "authorization_details": [ { "type": "mission", "mission_ref": "mr_7M9Qx2" } ] } ``` The authorization request should be submitted via Pushed Authorization Request (PAR, RFC 9126). PAR keeps the Mission reference, delegation state, and any additional context out of browser redirect URIs and server logs. The AS issues a mission-bound token that carries a projected Mission reference but is not itself a portable mission credential. ### Step 6: Token exchange for resource-specific APIs When the agent actually needs to call Calendar, it uses token exchange. The AS checks: - the Mission is still active - the target calendar resource falls inside the Mission's compiled authority region - the requested operation fits the Mission constraints - delegation depth has not been exceeded The AS then issues a Calendar-specific token carrying a projected Mission reference. The same process happens again for Email and CRM. This is where mission continuity is preserved without issuing one overly broad token up front, and without requiring the system to pre-enumerate every exact object the agent may touch. ### Step 7: Request-time enforcement At request time: - a baseline Resource Server may simply validate the access token and log a projected Mission reference - a gateway may query policy using Mission-derived context - a mission-aware RS may use introspection or token claims to apply additional checks This gives a deployment several enforcement points without requiring every backend service to understand the full Mission object. ### Step 8: Mission completion or revocation When the task completes, or if the user or enterprise revokes it, the Mission state changes. After that: - further token exchange fails - refresh or re-issuance tied to the Mission fails - already-issued short-lived tokens expire naturally or are cut short through eventing and revocation mechanisms That is the core difference from ordinary token-centric patterns: the authority object survives across token lifetimes, and can also end independently of them. ## OAuth Protocol Details Once approved, OAuth requests reference the Mission. ### Provisional primary path: RAR-based embedding The preferred direction is to reference an approved Mission through `authorization_details`: ```json { "authorization_details": [ { "type": "mission", "mission_ref": "mr_7M9Qx2" } ] } ``` This reuses an existing OAuth extension point and frames the Mission reference as structured authorization input, which seems more likely to be acceptable to OAuth practitioners. The `"mission"` type identifier requires IANA registration under the Authorization Details Types registry established by RFC 9396 Section 10. The identifier name is a candidate proposed for community feedback and is subject to change before any formal registration is made. Feedback on whether `"mission"` is the right name for this registry entry is one of the explicit questions for this blog RFC. ### Transport: PAR as the default Authorization requests carrying a mission reference should be submitted via Pushed Authorization Request (PAR, RFC 9126) by default. PAR submits the request body over server-to-server TLS before the browser redirect, keeping `mission_ref`, purpose parameters, and delegation state out of browser redirect URIs, referrer headers, and server logs. For any deployment that takes Mission-Bound OAuth seriously as a security primitive, PAR should be treated as a baseline requirement rather than an optional hardening measure. For interactive user-delegated Mission flows, PKCE (RFC 7636) is required for public and native clients. For confidential clients using PAR with private_key_jwt or client_secret authentication, PKCE is strongly recommended but not required, because the authorization code is already bound to an authenticated client credential. This aligns with RFC 9700 (OAuth 2.0 Security Best Current Practice). PAR remains required as a baseline for all client types regardless of PKCE applicability. **Mission reference binding at authorization code issuance**: when the AS receives a PAR request containing `authorization_details` with a `mission_ref`, the AS MUST bind that Mission reference to the resulting authorization code at the time the code is issued. At code exchange time, the client MUST NOT be permitted to present a different `mission_ref` than the one bound to the authorization code. If the code exchange request includes `authorization_details` with a different `mission_ref`, the AS MUST reject the request with `invalid_grant`. This prevents an adversary from substituting a lower-authority Mission reference for a higher-authority one at the final issuance step. The AS-bound Mission reference from the PAR step governs the issued access token regardless of what the client submits at code exchange. **Artifact binding**: the authorization code, the resulting primary mission-bound access token, and any refresh token issued from that code SHOULD all be bound to the same Mission version at issuance time. The AS should retain an internal binding record linking: - authorization code -> `mission_ref` - primary access token `jti` -> `mission_id` - refresh token handle -> `mission_id` - Approved Mission version -> Mission Authority Model version These bindings make substitution, replay, and audit reconstruction failures easier to detect and prevent. ### Authorization request parameter: not recommended A `mission_ref` query parameter on the authorization redirect (`GET /authorize?mission_ref=...`) is not a viable alternative for production deployments. Mission references appearing in redirect URIs are exposed in browser history, referrer headers, and server logs. PAR was specifically designed to eliminate this exposure. Deployments MUST use PAR for all Mission-referencing authorization requests. The GET parameter form MUST NOT be used. ## Mission-Bound Token Model An access token issued under Mission-Bound OAuth is still an audience-specific OAuth access token. It is not a portable mission credential. Its special property is that it is derived from an active Mission and can carry a reference to that Mission. **Initial mission-bound token audience**: the primary mission-bound access token issued at Step 5 (the OAuth authorization flow, before any token exchange) is an orchestration-layer credential. Its `aud` value is the orchestration layer's registered resource URI or the orchestration layer's `client_id`. This is a deployment requirement: the orchestration layer MUST be registered as an OAuth resource at the AS with a discoverable resource URI, OR the AS must support `client_id` as a valid `aud` value for the primary mission-bound token. The deployment profile MUST specify which model is used. Using `client_id` as `aud` is simpler and avoids requiring a separate resource registration for the orchestration layer; using a resource URI is more consistent with RFC 8707 audience binding conventions and is the recommended approach for multi-tenant or cross-domain deployments. Either way, the primary token is not intended for direct RS consumption. RSes receive mission-authority by way of audience-specific tokens produced through subsequent token exchange, each of which carries a `mission_ref` but targets a specific RS audience. This separates the mission-authority credential (held by the orchestration layer) from resource-access credentials (consumed by RSes and gateways). The Mission reference may appear: - inside the access token as a `mission_ref` or profile-equivalent claim - in introspection metadata - in exchange inputs and outputs - in audit and event streams The AS needs to validate Mission state before every downstream issuance decision. A Mission reference is useful for continuity, but over-exposing it creates privacy and linkability costs. The provisional standardized claim name for the projected Mission reference in tokens is `mission_ref`. This is consistent with the IANA registration candidate in the JWT Claims Registry section of this document. The AS-internal identifier remains `mission_id` and is never exposed at protocol boundaries. The claim name `mission_ref` is proposed for community feedback and may be adjusted before formal registration, but within this document it is used consistently as the normative name. Possession of `mission_ref` alone grants no authority. Every use of `mission_ref` MUST be bound to an authenticated client context and, where token-based authority is being exercised, to the sender-constrained token or token-derived subject through which the request is made. ### Composition with audience-bound tokens When a mission-bound token is issued for a specific resource, it is still an audience-specific access token. The Mission reference claim is additive: it appears alongside, not instead of, the standard audience-specific token claims. The AS composes both: the token is valid for the target audience AND references the Mission from which its authority derives. This means a mission-bound calendar token and a mission-bound CRM token produced from the same Mission may carry the same or different projected Mission references depending on deployment policy. They still derive from the same internal Mission, but the externally visible handle may be audience-specific. That is how the architecture balances continuity with privacy. ## Sender Constraining Sender constraining is a core requirement for Mission-Bound OAuth, not optional hardening. Without it, Mission-reference continuity becomes replay continuity. A stolen mission-bearing token carries both the audience-specific access permissions and a durable handle that links the token to a broader mission authority chain. DPoP (RFC 9449) or mutual TLS (mTLS, RFC 8705) binding should be stated as a baseline expectation for any mission-bearing token, including both the primary mission-bound access tokens and any tokens produced by mission-scoped exchange. A deployment profile that does not require sender constraining should make that gap explicit and acknowledge the replay risk it accepts. ## Mission Introspection Mission introspection is defined as an extension of OAuth Token Introspection (RFC 7662) rather than a new endpoint, to allow reuse of existing introspection client libraries and authorization infrastructure. A Mission-aware AS MUST support Mission introspection at its RFC 7662 introspection endpoint by accepting a `mission_ref` value as the `token` parameter: ```text POST /introspect Content-Type: application/x-www-form-urlencoded Authorization: Bearer token=mr_7M9Qx2&token_type_hint=mission_ref ``` The AS recognizes the `mission_ref` token type hint and returns Mission state as additional fields in the standard RFC 7662 introspection response: ```json { "active": true, "mission_state": "active", "purpose": "urn:example.com:mission:schedule-meeting", "exp": 1773072000, "delegation": { "max_depth": 1, "current_depth": 0 }, "authority_model": { "allowed_operations": ["calendar.schedule", "crm.record_activity"], "constraints": { "region": "EU" } } } ``` **Introspection response tiering**: the `authority_model` field in the introspection response exposes high-value Mission enforcement data and MUST NOT be returned to all introspection callers. The AS MUST require the introspection client to present an access token with scope `mission:introspect:authority` (or an equivalent deployment-defined scope) to receive the `authority_model` section. A caller presenting only a basic introspection credential receives `active`, `mission_state`, `purpose`, `exp`, and `delegation` but not `authority_model`. This prevents RSes that are authorized to check token validity from receiving the full authority region of every Mission they encounter. **Tenant-scoped introspection**: Mission introspection MUST be tenant-scoped. The AS MUST reject introspection requests where the authenticated caller is outside the tenant or trust boundary associated with the referenced Mission unless the deployment explicitly permits that class of cross-tenant enforcement. A new `token_type_hint` value `mission_ref` is a candidate for registration in the OAuth Token Type Hints registry. When the AS receives this hint, it MUST look up the Mission record rather than a token record. The `active: false` response MUST be treated as a hard block on further execution at any enforcement point. The `mission_state` field carries the precise semantic: `suspended` means execution is blocked pending resumption (the Mission may recover); `revoked`, `completed`, and `expired` are terminal (a new Mission is required). Enforcement points MUST consult `mission_state` to determine the correct agent behavior. They MUST NOT treat all `active: false` responses as equivalent to `mission_revoked`, as this would cause agents to abandon recoverable suspensions. **Introspection failure behavior**: enforcement points MUST treat introspection endpoint failures (network errors, 5xx responses, or responses arriving after the enforcement point's configured timeout) as `active: false`. Fail-closed behavior is required. A cached `active: true` response MAY be used only within a policy-defined staleness window; enforcement points MUST re-fetch when the staleness bound is exceeded or when a CAEP `mission-terminated` event is received. The staleness window MUST be defined explicitly in the deployment profile and MUST NOT default to unlimited. The architectural decision is: - the core Mission-Bound OAuth story does not require every deployment to expose Mission introspection - deployments that want RS- or gateway-side live Mission checks should use an introspection profile - the core protocol still needs to define what Mission state means at issuance, refresh, and exchange checkpoints even if no RS ever introspects it ## Token Derivation and Exchange Mission-Bound OAuth expects token exchange to be part of the normal mission execution path when agents call multiple downstream APIs or when one service delegates to another. **Subject token type**: when the subject token is a mission-bound access token, the `subject_token_type` is `urn:ietf:params:oauth:token-type:access_token` per RFC 8693. The AS distinguishes a mission-bound AT from a plain AT by the presence of a `mission_ref` claim in the JWT body. A new `subject_token_type` URI for mission-bound tokens is not proposed; the existing access token type is sufficient. The key rule is: > exchanged tokens may only represent authority that is still permitted by the referenced Mission at the moment of exchange. That means token exchange must evaluate: - Mission lifecycle state - Mission expiry - resource and action constraints against the compiled authority region - delegation depth - client identity - any policy conditions required by the deployment If the Mission is no longer valid, the exchange fails even if the input token itself is otherwise structurally valid. **Refresh tokens on exchange-derived tokens**: RFC 8693 does not mandate that token exchange responses include refresh tokens. By default, token-exchange-derived tokens under a Mission MUST NOT include a refresh token unless the AS policy explicitly permits it for the target resource and client combination. If the AS does issue a refresh token for an exchange-derived token, the AS MUST bind that refresh token to the same `mission_id` as the subject token and MUST revoke it when the Mission is revoked, suspended, or completed, following the same lifecycle rules as refresh tokens issued at initial authorization. An exchange-derived refresh token MUST NOT outlive the Mission from which its authority derives. ### Token Exchange Request Format The preferred exchange model is that the subject token already identifies exactly one Mission through its `mission_ref` claim, and the exchange request MAY echo that Mission reference in `authorization_details` when the client wants explicit binding: ```text POST /token Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:token-exchange &subject_token= &subject_token_type=urn:ietf:params:oauth:token-type:access_token &requested_token_type=urn:ietf:params:oauth:token-type:access_token &resource=https://calendar.example.com/ &scope=calendar.schedule &authorization_details=[{"type":"mission","mission_ref":"mr_7M9Qx2"}] ``` Embedding `mission_ref` inside `authorization_details` is preferred over a standalone token exchange parameter because RFC 9396 already defines `authorization_details` as a valid token endpoint parameter. A standalone `mission_ref` parameter would require IANA registration in the OAuth Parameters registry before conformant ASes could rely on it, since RFC 8693 Section 2.1 defines a closed parameter set and unregistered parameters may be silently ignored. The AS validates the Mission's state, checks the requested resource and scope against that Mission's compiled authority region, and issues a resource-specific token. The resulting token carries a `mission_ref` appropriate for the target audience. Mission selection rules: - if the subject token carries exactly one `mission_ref` and the exchange request omits Mission reference input, the AS MAY use the bound `mission_ref` from the subject token - if the exchange request includes `authorization_details` with `mission_ref`, the AS MUST compare that value to the Mission reference bound to the subject token and reject the request on mismatch - if the subject token does not uniquely identify one Mission and the request omits Mission reference input, the AS returns `mission_ref_required` This keeps Mission selection explicit where needed, but avoids forcing well-behaved orchestration runtimes to copy the same `mission_ref` through every exchange hop purely for disambiguation. **Anti-confused-deputy rule**: token exchange MUST validate not only the Mission but also the requesting client's authority to derive a token for the requested target resource under that Mission. A client MUST NOT use another client's mission-bound subject token as exchange input unless that delegation path was explicitly authorized by the Mission and represented in the delegated actor state. Possession of a structurally valid subject token is not sufficient by itself. The cleanest delegation story is to treat delegation as a constrained form of downstream token derivation, enforced at exchange time by the AS, rather than as an informal client-side action. ## Delegation Model Delegation is in scope because many missions are not executed by a single software component end-to-end. The `act` claim defined in RFC 8693 Section 4.1 identifies the current acting party in a delegated token. RFC 8693 defines `act` as a single JSON object, not a recursive structure. Nested `act.act` is not defined by RFC 8693 and is not supported by most JWT libraries. For multi-hop delegation chains, Mission-Bound OAuth proposes a `delegation_chain` claim as an ordered array of actor identifiers. Index 0 is the most-recently-added actor (the current immediate delegate, matching `act.sub`); the last index is the originating delegating actor. The array grows at the tail as delegation chains extend. This is a proposed extension beyond RFC 8693 and is one of the explicit questions for community feedback. A two-hop delegation example: ```json { "sub": "user-123", "sub_profile": "user", "act": { "sub": "assistant-agent", "sub_profile": "ai_agent" }, "delegation_chain": [ { "sub": "assistant-agent", "sub_profile": "ai_agent" }, { "sub": "workflow-engine", "sub_profile": "service" } ], "mission_ref": "mr_7M9Qx2" } ``` The `act` claim identifies the current actor (the immediate delegate). The `delegation_chain` records the full ordered chain for audit and RS policy evaluation. The AS is authoritative for the chain state; both claims are projections of that state into the token. Whether to extend RFC 8693 with a standardized multi-hop chain representation or define a Mission-specific claim is an open question for feedback. The `delegation_chain` proposal is one candidate. Feedback on the claim name, structure, and whether this requires a standalone Internet-Draft is explicitly requested. The current direction for the delegation model: - delegation is allowed only if the Mission permits it - each delegation event extends `act` (current actor) and appends to `delegation_chain` (full history); **one delegation event is defined as one token exchange request that introduces a new actor**: the AS increments `current_depth` by exactly one for each exchange that sets or changes the `act` claim in the resulting token; re-exchanges that produce a token for the same actor at the same depth do not increment `current_depth` - maximum delegation depth is enforced by the AS at exchange time via an atomic increment (see Concurrency Requirements below) - delegated actors inherit attenuated, not expanded, authority - the AS is authoritative for delegation state; tokens carry only the minimum chain data needed for the next hop or RS policy **Offline delegation chain validation limitation**: once issued, the `act` and `delegation_chain` claims in a token are immutable for the token's lifetime. A delegation revocation at the AS does not retroactively alter these claims in already-issued tokens. Resource servers that validate delegation offline cannot detect post-issuance chain revocations. Mission-aware resource servers requiring strong delegation assurance MUST use Mission introspection rather than relying solely on token-embedded chain claims. This is an intentional design constraint of bearer token delegation and is not unique to Mission-Bound OAuth. ## Verified Agent Binding Authentication establishes who approved the Mission. Verified agent binding is the separate question of proving that the actor executing derived actions is the same actor the Mission approved, continuously, across every token exchange, cross-domain projection, delegation hop, and Mission fork the execution takes. This is an authority continuity problem, not an authentication syntax problem. Mission approval, whether through an interactive consent flow, a policy-auto-approved proposal, or a pre-provisioned activation, establishes that a specific principal delegated authority to a specific actor for a specific purpose. Verified agent binding ensures that the actor presenting mission-bearing tokens at exchange time is the actor that was approved to do so, and that this binding holds for the full Mission lifecycle rather than only at issuance. ### The Binding Anchor The Mission record at the AS establishes the binding anchor at approval time. Three fields define the approved actor context: - `mission_subject.sub`: the human principal on whose behalf authority was delegated - `mission_client.client_id`: the registered OAuth client or orchestration layer approved to operate under this Mission - `delegation`: the actors or actor classes permitted to hold derived tokens, and at what depth The AS is the authoritative source for these bindings. Clients do not self-assert actor identity at exchange time; the AS validates the requesting client against the Mission's recorded approval context at every derivation step. ### Key Continuity via Sender Constraining Sender constraining (DPoP, RFC 9449, or mTLS, RFC 8705) is the mechanism that binds token authority to a specific key holder across the Mission's execution. For mission-bearing tokens, key continuity is the protocol expression of actor continuity. The binding rules across the Mission's execution: - **Primary mission-bound token**: the orchestration layer's DPoP key thumbprint (`cnf.jkt`) is bound to the primary access token at issuance. This establishes the key identity of the approved executor. - **Exchange-derived tokens**: when the orchestration layer exchanges the primary token for an audience-specific token, the AS binds the resulting token to the requesting client's DPoP key. An exchange presented with a different key signals a different actor. The AS MUST reject exchanges where the DPoP key does not match the key bound to the subject token unless the Mission's delegation model explicitly permits delegation to a new key holder at that depth. - **Delegated actors**: when the Mission permits delegation and a new actor is introduced via token exchange, the AS records the new actor in `act` and appends to `delegation_chain`. The delegated token is bound to the delegate's DPoP key. That delegate's key identity must be stable across subsequent re-exchanges at the same depth. The practical consequence is that a stolen mission-bearing token cannot be used to derive downstream tokens by an unauthorized actor, because each exchange requires proof of possession of the bound key. Key continuity is actor continuity for every derivation step the Mission takes. ### Actor Rebind, Key Rotation, and Executor Failover The architecture also needs a legitimate continuity story for when the approved executor changes keys or moves runtimes without changing authority. Long-running Missions will eventually encounter key rotation, process restart, regional failover, HSM rollover, or planned migration from one orchestration instance to another. If the architecture treats every new key as a new actor with no rebind path, Missions become too brittle for real deployments. If it silently accepts key changes, verified agent binding collapses. The right model is **controlled rebind**, not silent continuity: - the Mission keeps an approved executor identity anchored in `mission_client.client_id` - sender-constrained keys are continuity artifacts for that executor, not the executor identity itself - rotating or replacing the bound key requires an explicit AS-mediated rebind event - the AS authenticates the requesting client, verifies it is the approved executor or an authorized delegate at the current depth, records the new key binding, and emits a signed audit event - a rebind does not expand authority, reset delegation depth, or bypass lifecycle checks; it only updates the continuity anchor for the same approved actor Architecturally, this should be treated like suspension and resumption: a governed lifecycle-adjacent operation with audit semantics, not an implementation convenience hidden behind token issuance. Deployments may choose whether key rebind requires step-up authentication, administrator approval, or policy-only approval based on Mission sensitivity, but the existence of a controlled rebind path should be explicit. ### Exchange-Time Actor Verification At every token exchange, the AS performs actor verification against the Mission's approved context. This happens independently of whether the subject token is structurally valid: 1. **Client identity check**: the requesting `client_id` must match either the Mission's `mission_client.client_id` for orchestration-layer exchanges, or a delegated actor identity recorded in the Mission's delegation state for sub-delegated exchanges. An exchange from an unauthorized `client_id` MUST be rejected even if the subject token passes all other validation checks. 2. **Delegation depth check**: the AS verifies the exchange does not introduce a new actor beyond the Mission's `max_depth`. The check is atomic (see Concurrency and Atomicity Requirements). An actor-expanding exchange that would exceed `max_depth` is rejected with `mission_delegation_depth_exceeded`. 3. **Actor chain integrity**: the AS derives `act` and `delegation_chain` from its own Mission state and the authenticated requesting client. Client-supplied actor claims in exchange requests are not authoritative and MUST NOT be accepted as-is. The AS is the only party authorized to set or extend these values in derived tokens. 4. **Anti-confused-deputy enforcement**: the AS validates that the requesting client is authorized to derive a token for the requested target resource under the Mission. Possession of a structurally valid subject token is not sufficient by itself. This check prevents one actor from using another actor's mission-bearing token as exchange input to obtain authority for an audience the original actor did not intend to grant. These checks compose into a chain: each exchange step verifies the requesting client against the Mission's recorded approval context, verifies key possession, verifies delegation depth, and verifies that the derived authority remains inside the Mission's authority model. No single step alone is sufficient. ### Binding Across Projections When Mission authority crosses a trust domain boundary via a cross-domain assertion or ID-JAG projection, actor binding must carry with it. The receiving AS does not have access to the originating AS's Mission record, so actor continuity across trust boundaries depends on what the assertion explicitly carries. The projection carries `act` and `delegation_chain` as they existed at assertion issuance time. The receiving AS uses these to apply local policy. For example, the receiving AS may permit only agent-type actors under a registered `client_id` to derive tokens for its governed resources. Two limitations are inherent to projection-based actor binding and MUST be acknowledged explicitly in any cross-domain deployment: - **Stale chain state**: the assertion is a point-in-time projection. Post-issuance delegation chain changes, revocations of specific delegation hops, or suspension of an actor within the chain are not visible to the receiving AS from the assertion alone. - **No live depth enforcement**: the receiving AS cannot enforce the originating Mission's `max_depth` limit against future exchanges it may authorize, because it does not hold the originating Mission's delegation state. The trust split is easiest to see directly: | Guarantee | Home domain with AS access | Cross-domain via projection only | |---|---|---| | Mission lifecycle state is current | Yes | Not necessarily; may be stale | | Actor identity is verified against Mission record | Yes | Only to the extent the projection carries trustworthy actor state | | Delegation depth can be enforced live | Yes | No | | Mission Authority Model can be evaluated in full | Yes | No, only projected facts are available | | Revocation or suspension is visible immediately | Yes, subject to cache bounds | No, unless live introspection or equivalent state sharing exists | | Anti-confused-deputy checks can use full Mission context | Yes | Only within the reduced context carried across the boundary | Mission-aware deployments that require live actor verification across trust boundaries MUST use mutual introspection or equivalent live state channels rather than relying on static projection. Deployments that accept projection-only binding must treat cross-domain actor continuity as best-effort rather than authoritative. ### Mission Forks and Sub-Mission Actor Inheritance When a Mission spawns a parallel sub-task requiring its own Mission record rather than progressive expansion of the existing one, actor binding must be established for the sub-Mission explicitly at proposal time. Two models apply: **Sub-Mission under the same orchestration layer**: the same `mission_client.client_id` proposes and holds both Missions. The actor binding is continuous; the same orchestration layer is the approved executor for both. No additional binding ceremony is required. **Sub-Mission delegated to a different actor**: if the sub-Mission is proposed for a different executing actor (a sub-agent, a downstream service, or a different orchestration instance), that actor must be identified at proposal time and the Mission's delegation bounds must permit it. The sub-Mission's `mission_client` records the sub-actor identity. The parent Mission's delegation chain is not automatically inherited by the sub-Mission; the sub-Mission is a distinct authority object with its own actor binding anchored independently at the AS. In both cases the key rule holds: actor identity at sub-Mission creation is established explicitly at the AS when the sub-Mission is approved, not inferred from parent Mission delegation state. ### Parent and Sub-Mission Lifecycle Coupling Sub-Missions also need explicit lifecycle coupling to the parent Mission. Without it, the architecture can accidentally recreate the same overhang problem it is trying to solve: a parent Mission ends, but a child authority object continues executing because it has its own local lifecycle and no normative dependency on the originating business authority. The safest default is: - a sub-Mission records the `mission_ref` of its parent as part of its governance metadata - a sub-Mission MUST NOT outlive the parent Mission's terminal state unless it was approved as an intentionally independent successor Mission - parent `revoked`, `expired`, or `completed` transitions cascade to dependent sub-Missions unless policy explicitly classified them as independent - parent `suspended` transitions suspend dependent sub-Missions by default, because the authority question is still unresolved - resuming a parent Mission does not automatically resume all children unless the deployment chose coupled resumption semantics at approval time This keeps hierarchy honest. A sub-Mission may be its own authority object, but it is not free-floating by default. If a deployment wants a child workflow to continue after the parent ends, that should be explicit at approval time and visible in audit as a new, independently rooted authority path rather than an implicit inheritance loophole. ### The Binding Invariant The verified agent binding invariant for Mission-Bound OAuth is: > For every token derived from an active Mission, the AS can identify exactly which actor is bound to that token, verify that actor against the Mission's approved delegation context, and trace the full actor chain from the approved orchestration layer to the current token holder. This invariant is maintained by the Mission record as the binding anchor, sender-constraining as the key-identity enforcement mechanism, AS-authoritative actor claims in derived tokens, atomic delegation depth enforcement, and anti-confused-deputy validation at each exchange step. The invariant degrades under two conditions that deployments must treat as explicit risk decisions: (1) bearer tokens without sender-constraining, which allow any possessor to present the token at exchange time without proving key identity; and (2) cross-domain projection without live introspection, which allows the receiving AS to act on stale actor state. Both are known deployment tradeoffs. The invariant holds for the home domain under sender-constrained, Mission-aware issuance and degrades proportionally as deployments depart from that baseline. ## Resource Server Model One important question is what a Resource Server should be able to rely on. A practical processing model is: - the AS enforces Mission lifecycle and delegation rules at issuance, refresh, and exchange time - the RS continues to validate audience-specific access tokens as usual - the RS may receive selected Mission metadata through token claims or introspection - the RS must not be required to understand the full Mission object to remain interoperable This keeps Mission-Bound OAuth from turning every RS into a mission engine while still allowing richer enforcement where deployments want it. If richer RS behavior is desired, it should be profiled separately: | RS Tier | Behavior | Deployment Requirement | |---|---|---| | **Baseline RS** | Validates access token as usual; optionally consumes a projected Mission reference for audit or logging | No Mission-specific changes beyond a scoped token | | **Introspecting RS** | Queries the AS introspection endpoint using the Mission introspection profile to retrieve live Mission state before processing the request | Network access to the AS introspection profile | | **Policy-aware RS** | Uses Mission-derived attributes (purpose, authority region, delegation state) in local authorization decisions via AuthZEN or an equivalent PDP | Full Mission metadata integration and PDP access | This is one of the most important separations in the architecture because it allows incremental deployment. Mission-Bound OAuth should still deliver value when only the AS is mission-aware. ## Mission Authority and Scope Authority Mission authority is a further constraint applied on top of scope authority, not a replacement for it. The scope model is hybrid: - the client may request scopes as part of the authorization request, as it does today - the AS treats client-requested scopes as inputs, not as authoritative claims - the AS derives the final granted scopes from the Mission's authority model, narrowing or adjusting the client's request to match what the Mission permits - the resulting token carries scopes that are a subset of both what the client requested and what the Mission's authority model allows This keeps the architecture backward compatible. A baseline RS that does not understand Mission references still receives standard OAuth scopes in the token and can enforce them as usual. The Mission adds a governed layer above scope: the AS ensures at issuance that no token carries scope authority that exceeds the Mission's authority model, regardless of what the client requested. The practical implication: if a client requests `calendar:write` but the Mission's authority model only permits write access to user-manageable calendars during the current business process, the AS may issue a more specific scope (or a standard scope paired with constrained audience claims) reflecting the narrower authority. The AS is the final arbiter of what scope appears in the token; the client's scope request is advisory. **Scope mapping**: the mechanism by which the AS maps authority-model elements (resource type selectors, operation groups, relationship predicates) to OAuth scope strings is not standardized in this version and is implementation-specific. The normative constraint is: the AS MUST NOT issue a scope value that grants authority exceeding the Mission's authority model. The practical implication is that baseline RSes receive AS-derived scopes that conservatively represent Mission-attenuated authority, but the exact scope string for a given authority model is determined by AS implementation and deployment configuration. Interoperable scope mapping is a subject for deployment profile work, not the core spec. For a baseline RS that does not understand Mission references, scope remains the effective authorization floor. Mission constraints are only as effective as the enforcement points that evaluate them, which is an intentional design tradeoff that enables incremental adoption. It should be stated explicitly: the hybrid model reduces but does not eliminate the over-authorization risk at baseline RSes, because the AS-derived scope still reflects the Mission's authority model. ## Mission-Aware Client Registration Which Mission types a client is permitted to request should be part of client registration (RFC 7591 extension). A client that has not been registered for `schedule_meeting` cannot request a Mission of that type, regardless of what it asserts at runtime. Client registration metadata should include the following candidate fields: - `mission_types`: an array of permitted `purpose` identifiers or purpose classes the client may propose; the AS rejects proposals referencing purposes not in this list - `mission_delegation_max_depth`: the maximum delegation depth permitted for this client across all Mission types; defaults to `0` (no delegation) if absent - `mission_approval_mode`: the required approval mode for this client's proposals: `"interactive"` (user consent required), `"policy_auto"` (AS evaluates against registered policy at proposal time), or `"pre_provisioned"` (Mission type is pre-approved and activates immediately on request) - `mission_resource_categories`: an optional coarse-grained filter on the resource type categories the client may reference in proposals, applied before template-level constraints These field names are candidates for registration in the OAuth Dynamic Client Registration Metadata registry per RFC 7591 Section 3.2, not as JWT claims. Feedback on naming and structure is part of what this blog RFC is intended to surface. This is the allow-list mechanism applied at the authorization layer. Without it, any Mission-capable client can request any Mission type and the AS has no normative basis for rejection beyond local policy. Client registration is the provisioning boundary that separates what was pre-authorized by an administrator from what a client can self-assert at runtime. # Mission Management The prompt itself is not the authorization artifact. It is an input to interpretation and proposal creation. The basic architectural assumptions are: - prompts are untrusted semantic input - interpreted intent is a proposal, not authority - the approved Mission is the first artifact with normative authority semantics ## Mapping Pipeline The prompt-to-mission mapping process consists of: 1. Prompt interpretation 2. Intent extraction 3. Mission template selection 4. Mission proposal generation 5. Mission approval 6. OAuth authorization and token issuance ## Intent Envelope An agent or client may convert a prompt into an intermediate representation called an **Intent Envelope**. Example: ```json { "intent_type": "schedule_meeting", "entities": { "participant": "Dana", "time_window": "next week" }, "requested_outcomes": [ "calendar.create_event", "crm.create_note" ], "risk_signals": { "external_communication": false, "financial_action": false, "sensitive_data": false }, "confidence": 0.92 } ``` The Intent Envelope expresses the agent's interpretation of the prompt. It does not itself create authority. ## Mission Templates Authorization servers or associated control-plane services may maintain a registry of **mission templates** representing common workflow categories. Example template identifiers: - `schedule_meeting` - `customer_followup` - `expense_submission` - `travel_booking` Templates may define: - resource types and selectors - operation groups - default mission constraints - delegation limits - approval mode - step-up or administrator approval requirements - business-process conditions - compliance and jurisdiction boundaries Templates are useful because they constrain how free-form prompts become structured authority requests. They are also the appropriate level at which enterprise security and governance teams author policy, without requiring application teams to define raw resource taxonomies for every Mission type. **Minimum template schema**: a Mission template is a JSON object with the following structure: ```json { "template_id": "schedule_meeting", "purpose_class": "urn:example.com:mission:schedule-meeting", "display_name": "Schedule a Meeting", "authority_model_defaults": { "allowed_resources": [ { "type": "calendar.event", "selector": "user-manageable-calendars" } ], "allowed_operations": [ { "group": "calendar.schedule" } ], "constraints": [] }, "delegation": { "allowed": false, "max_depth": 0 }, "lifecycle": { "max_duration_seconds": 900 }, "approval_mode": "interactive", "requires_step_up": false } ``` Required fields: `template_id`, `purpose_class`, `display_name`, `authority_model_defaults`, `approval_mode`. Optional fields: `delegation`, `lifecycle`, `requires_step_up`, and deployment-specific extension fields. Templates are registered at the AS via a template registration API (a Layer 2 management-plane capability). Clients reference a template in a proposal by `template_id`. The AS MUST validate that the proposal's candidate authority is a strict subset of the template's `authority_model_defaults` before approving. A proposal that exceeds the template's authority bounds MUST be rejected. ## Purpose Taxonomy Purpose identifiers need a clearer IAM story because they drive templates, client registration, approval policy, and audit semantics. The taxonomy distinguishes three levels: | Level | Form | Audience | Stability | |---|---|---|---| | **Display purpose** | Human-readable string | Approval UX, end users | Presentational only; may change | | **Template identifier** | Short deployment-local string (e.g., `schedule_meeting`) | Template selection at the AS | Stable within a deployment | | **Policy class** | URI (e.g., `urn:example:mission:schedule-meeting`) | Client registration, policy engines, audit, cross-deployment interoperability | Globally stable; registration-controlled | The policy class URI is the authoritative identifier. It is what appears in `mission_types` client registration metadata, in AS policy rules, and in audit events. URI form is chosen because: - it provides a namespace that avoids collisions between deployments and organizations - it enables future standardization of well-known purpose classes without requiring a flat global string registry - it is consistent with how OAuth, OIDC, and related specs handle stable identifiers (e.g., scope URIs, grant type URIs) In simple single-deployment scenarios, the template identifier and policy class may be the same string. The display purpose is always separate because it is a UX artifact, not a policy artifact. Organizations defining their own purpose classes should use domain-based URI namespaces: `urn:example.com:mission:schedule-meeting` or `https://example.com/mission-classes/schedule-meeting`. Standard or widely-shared purpose classes are a future registry concern; the architecture does not attempt to define them now. The important property is stable policy reference. Clients, administrators, and policy engines need a URI they can register against and reason about consistently, independent of how the display label changes over time. ## Tenant and Organization Boundary Most IAM deployments are tenant- or organization-scoped. The safest default is to treat a Mission as tenant-bound unless it is explicitly projected across a federation boundary. A Mission should at least carry: - tenant or organization identifier - subject tenancy - client tenancy - policy authority or issuer This matters because: - relationship predicates often depend on tenant-local graphs - Mission introspection must not leak Mission state across tenants - client registration and purpose classes are usually tenant-scoped - cross-domain Mission assertions are explicit exceptions, not the default The safest default is: - Missions are local to one issuer and one tenant boundary - anything that crosses that boundary does so through an explicit projected artifact and trust decision Operationally, this means `mission_ref` resolution must also be tenant-scoped: - the AS MUST reject `mission_ref` lookups, introspection requests, authority-model retrieval, and exchange requests that originate outside the tenant or issuer context that owns the Mission unless an explicit federation profile permits that access - a `mission_ref` that is valid in one tenant MUST NOT be assumed valid or meaningful in another tenant, even if the string value collides ## Proposal and Approval ### Endpoint Candidates Current endpoint candidates: ```text POST /mission-proposals POST /mission-proposals/{proposal_id}/approval GET /mission-proposals/{proposal_id} GET /missions/{mission_ref} POST /missions/{mission_ref}/resume POST /missions/{mission_ref}/expand ``` The current intent is: - `POST /mission-proposals` creates a Mission Proposal based on interpreted intent - `POST /mission-proposals/{proposal_id}/approval` approves, rejects, or attenuates the proposal - `GET /mission-proposals/{proposal_id}` returns proposal state for polling or review - `GET /missions/{mission_ref}` returns the approved Mission artifact (authorization required; scoped to principals with administrative or subject authority over the Mission) - `POST /missions/{mission_ref}/resume` resumes a suspended Mission; requires the same authentication and authorization as the original approval action - `POST /missions/{mission_ref}/expand` submits an expansion proposal against an active Mission; see Progressive Mission Expansion ### Proposal Request Schema `POST /mission-proposals` accepts `application/json` with the following structure: ```json { "purpose": { "class": "urn:example.com:mission:schedule-meeting", "display": "Schedule a Meeting with Dana" }, "template_id": "schedule_meeting", "subject": { "sub": "user-123", "iss": "https://idp.example.com" }, "candidate_authority": { "resource_types": ["calendar.event", "crm.account_note"], "operation_groups": ["calendar.schedule", "crm.record_activity"], "constraints": { "region": "EU", "business_process": "meeting-followup" } }, "parameters": { "participant": "Dana", "time_window": "next week" }, "delegation": { "allowed": false }, "lifecycle": { "max_duration_seconds": 900 }, "display": { "title": "Schedule a Meeting", "description": "The assistant will check calendar availability and create a meeting with Dana.", "actions": ["Check your calendar for availability", "Create a calendar event with Dana"], "constraints": ["Expires in 15 minutes", "EU data only"] } } ``` Required fields: `purpose.class`, `subject`, `candidate_authority`. Optional fields: `template_id` (if omitted, the AS selects a template by purpose class), `parameters`, `delegation`, `lifecycle`, `display`. **Success response** (HTTP 201 Created): ```json { "proposal_id": "prop_Kx29Mf", "state": "pending", "created_at": 1773072000, "approval_uri": "https://as.example.com/mission-proposals/prop_Kx29Mf/approval", "status_uri": "https://as.example.com/mission-proposals/prop_Kx29Mf" } ``` When the proposal is approved, `GET /mission-proposals/{proposal_id}` returns the updated proposal record with `"state": "approved"` and a `mission_ref` field containing the projected Mission reference for the newly activated Mission: ```json { "proposal_id": "prop_Kx29Mf", "state": "approved", "created_at": 1773072000, "approved_at": 1773072120, "mission_ref": "mr_7M9Qx2", "mission_uri": "https://as.example.com/missions/mr_7M9Qx2" } ``` Clients MUST poll `status_uri` to detect approval. The AS MAY also support a `callback_uri` field in the proposal request body that it calls upon approval with the same response body. The `mission_ref` returned here is the value the client uses in subsequent `authorization_details` when starting the OAuth authorization flow. **Failure responses**: 400 for malformed requests, 401 for unauthenticated callers, 403 for unauthorized mission types (client not registered for the requested `purpose.class`), 422 for proposals that exceed template bounds. The approval step is where requested authority becomes real authority. Approval results in one of three outcomes: - denial, with no Mission created - attenuation, with an Approved Mission narrower than the proposal - approval, with an Approved Mission created from the proposal That approval may be performed by: - the end user - an administrator - enterprise policy - an external approval system - a combination of human and policy controls An attenuation step is explicitly in scope. The approved Mission may be narrower than the proposed one. ### Single-Party and Multi-Party Approval The document often talks about "the approver" for readability, but the architecture should not imply a single-actor approval model. Some Missions are low-risk and can be approved by the subject alone. Others require separation of duties: user plus administrator, administrator plus policy engine, or two human approvers from different roles. The architectural point is that approval is a governed decision procedure, not a single UI click. A Mission may therefore define: - one required approver class - multiple required approver classes - policy preconditions that must succeed before any human approval is sufficient - ordered approval stages for regulated workflows The output is still one Approved Mission artifact, but its approval evidence may record multiple approving principals, policy decisions, and timestamps. Separation-of-duties logic does not need to live in the core OAuth extension, but the architecture should acknowledge that the approval boundary may be multi-party for privileged or regulated Missions. There is a second distinction that matters in the same way: the delegating principal's intent and the resource owner's authority are not always the same thing. A manager may be authorized to start an HR-related workflow involving data that is ultimately governed by a separate data owner, compliance function, or regulatory policy authority. For low-risk workflows those inputs may collapse into one approval path. For sensitive data and regulated actions, they may need to remain distinct and both be reflected in Mission approval policy. The proposal model should allow input from: - a raw prompt - an intent envelope - a structured plan - an MCP tool schema extraction - a direct structured authority request That flexibility matters because not every deployment wants the AS itself to process natural language. ### Mission Proposal Authorization Who is the authorized principal to call `POST /mission-proposals` is a security-critical question. The design principle that agents interpret prompts but do not grant authority needs a concrete protocol expression at the proposal endpoint. The authorized callers and their trust levels: - **Orchestration layer or agent platform**: the system that manages agent execution, acting as an authenticated OAuth client; the AS authenticates the caller by `client_id` using standard OAuth client authentication; the platform is trusted to submit proposals on behalf of its managed agents but not to approve them - **User session**: an authenticated user may directly author or authorize a proposal through a consent flow; the AS authenticates the user through a standard OAuth authorization flow - **Administrator**: an authenticated administrator acting under elevated policy authority, able to pre-approve mission types or approve proposals for regulated workflows The agent runtime is not an authorized proposal caller. An agent should not be able to submit a proposal under its own identity without passing through an orchestration layer or authenticated user session. The proposal endpoint should reject unauthenticated or agent-self-authenticated requests. The critical separation: proposal submission is client-authenticated at the orchestration layer. Approval is user-authenticated or policy-evaluated. These are distinct trust steps enforced by separate authorization checks at the AS. A client registered for `schedule_meeting` missions can propose one; only the authorized approver can activate it. **User identity binding in `mission:propose` tokens for user-delegated missions**: a `mission:propose` access token obtained via client credentials allows the orchestration layer to submit proposals. But for user-delegated missions, the `subject` field in the proposal must be bound to a verified user identity. The AS MUST NOT accept a `subject.sub` claim in a proposal on the basis of the client's self-assertion alone. Three acceptable binding mechanisms: 1. **Session-bound `mission:propose` token**: the orchestration layer obtains the `mission:propose` token through an authorization code flow that authenticates the user. The AS records the authenticated user subject in the issued token. At proposal time, the AS validates that `proposal.subject.sub` matches the subject in the `mission:propose` token. 2. **JWT subject assertion**: the orchestration layer includes a signed JWT subject assertion in the proposal request, issued by the IdP that authenticated the user. The AS validates the assertion and binds the subject to the proposal. 3. **Pre-bound session reference**: the orchestration layer includes a session reference (e.g., an OIDC `id_token` `jti` or session ID) in the proposal. The AS resolves the authenticated subject from its own session store. A `mission:propose` token obtained via client credentials alone MUST only be used for headless missions where no interactive user subject is involved. For headless workflows, the orchestration layer or an administrative process is the authorized proposal submitter, and approval is delegated to policy rather than an interactive consent step. **Proposal endpoint authentication**: `POST /mission-proposals` is a protected resource requiring an access token with scope `mission:propose`, issued by the AS to the orchestration layer's `client_id`. The endpoint is not an OAuth grant endpoint; it does not accept client credentials directly. The AS MUST authenticate the caller as a registered OAuth client and validate that the client's registration includes the proposed mission type in `mission_types`. The grant type used to obtain the `mission:propose` token depends on the mission type: - **Headless missions**: the orchestration layer obtains the token via the client credentials grant (RFC 6749 Section 4.4). The resulting token carries no user subject and MUST only be used for headless mission proposals. The AS MUST reject any user-delegated proposal submitted under a client-credentials-derived `mission:propose` token. - **User-delegated missions (Mechanism 1)**: the orchestration layer obtains the token via the authorization code flow that authenticates the user. The AS records the authenticated user subject in the issued token. At proposal time, the AS validates that `proposal.subject.sub` matches the subject bound in the `mission:propose` token. This is the most direct binding mechanism. - **User-delegated missions (Mechanisms 2 and 3)**: the orchestration layer may obtain the `mission:propose` token via client credentials but must supplement the proposal with either a signed JWT subject assertion (Mechanism 2) or a pre-bound session reference (Mechanism 3) to establish the user subject. The AS validates the supplemental binding independently before accepting the proposal subject claim. The AS MUST publish the proposal endpoint URL in its authorization server metadata (RFC 8414) under a `mission_proposal_endpoint` metadata field. Clients discover the endpoint from AS metadata; the endpoint URL MUST NOT be hardcoded. The following scopes are candidates for registration. Feedback on scope naming and whether per-mission-type variants (e.g., `mission:propose:schedule_meeting`) are preferable to umbrella scopes is an explicit question for this blog RFC. | Scope | Grant Type | Purpose | |---|---|---| | `mission:propose` | client credentials or auth code | Submit Mission proposals at `POST /mission-proposals` | | `mission:activate` | client credentials | Activate pre-provisioned mission types at `POST /missions/activate` | | `mission:expand` | client credentials | Submit expansion proposals at `POST /missions/{mission_ref}/expand` | | `mission:authority-model:read` | client credentials | Retrieve signed Mission Authority Model artifacts | | `mission:introspect:authority` | client credentials | Receive `authority_model` in Mission introspection responses | ### Approval Authority Model Approval authority also needs a clear precedence model. The approval model should assume these authority sources, from strongest to weakest: - **hard policy deny**: cannot be overridden by user approval - **administrator approval or attenuation**: may grant or narrow within administrative scope - **subject approval**: grants delegated authority within the limits policy and registration allow - **policy auto-approval**: grants within pre-registered constraints for trusted clients Some consequences follow: - a user cannot approve what policy forbids - an administrator may attenuate a Mission even if the subject would have approved a broader one - policy auto-approval only works within pre-registered Mission classes and authority envelopes - external approval systems act as delegated approvers; they do not bypass issuer policy ## Approval UX and Consent Display The approval step is only meaningful if the approver understands what they are approving. Structured Mission proposals with resource types, operation groups, and relationship predicates are not legible to most users. The Mission proposal should carry a human-readable display representation alongside the machine-evaluable authority structure. This display representation is used in the approval UI, not in enforcement: ```json { "display": { "title": "Schedule a Meeting", "description": "The assistant will check calendar availability, create a meeting with Dana, send an email invitation, and log a CRM note. This access expires in 15 minutes.", "actions": [ "Check your calendar for availability next week", "Create a calendar event with Dana", "Send an email invitation to Dana", "Log a follow-up note in Salesforce for Dana's account" ], "constraints": [ "EU data only", "Accounts you own", "Expires in 15 minutes" ] } } ``` The `display` object is the consent primitive. Users approve the display representation; the system enforces the [Mission Authority Model](#mission-authority-model-as-a-stored-versioned-artifact). That alignment between what the user sees and what the system enforces is a security property, not a UX choice. Without it, the approval step is a checkbox users do not understand and the "human in the loop" guarantee is nominal. **Template-driven display validation** is the mechanism that preserves this alignment. The orchestration layer may supply a candidate `display` object in the proposal, but the AS validates it against the selected mission template before presenting it to the approver. The validation checks that: - every claimed action in `display.actions` maps to an operation group present in the authority model - every claimed constraint in `display.constraints` is actually present in the authority model - the display description does not omit material authority that the authority model grants If the AS cannot verify alignment, it either regenerates the display from the authority model (template-driven generation) or rejects the proposal. Accepting an unverified display representation is a social engineering attack surface: a malicious or compromised orchestration layer could describe a benign operation while the authority model permits something broader. Template-driven generation or AS-side validation is therefore a security requirement, not a UX convenience. ## A2UI as the Mission Interaction Layer The plain `display` object is a useful minimum, but it is not the only possible interaction model. For more agent-native deployments, [A2UI](https://a2ui.org/) is a strong fit as an optional Mission interaction layer: - the Mission Proposal remains the authority candidate - the Mission Authority Model remains the enforcement artifact - A2UI becomes the rendering and interaction layer for review, clarification, attenuation, approval, suspension, and remediation flows That is a better fit than a static `display` blob when the approval flow is conversational or multi-step: - the AS may need to ask clarification questions - the approver may want to narrow the Mission before approval - the client may need a structured remediation or resume action after suspension - different clients may want native UI rendering without executing arbitrary remote code The right architectural boundary is: - `display` is the minimum portable summary every deployment can support - A2UI is an optional richer interaction profile for agent-native clients - neither `display` nor A2UI is the authority itself - the Approved Mission and Mission Authority Model remain authoritative AAuth-like approval experiences become much easier to imagine in this model: the authorization server can drive a structured interaction surface while still keeping authority semantics at the Mission layer rather than in the UI layer. That separation matters. If the UI protocol becomes the authority artifact, the system becomes harder to audit and explain. If the UI protocol is only a presentation and interaction surface over Mission semantics, then: - approval remains governable - clarification remains structured - remediation can be standardized - the AS can validate what is shown against what is actually enforced The practical recommendation is therefore: - require a simple `display` summary in the base architecture - allow an A2UI interaction surface as an optional profile for richer clients - require AS-side validation that the A2UI view, like the `display` view, accurately represents the authority actually being approved ## Approval Evidence Artifact From an IAM governance perspective, it is not enough to know that a Mission was approved. The system also needs to retain what the approver was actually shown. The approval evidence artifact should include at least: - the Approved Mission identifier and version - the Mission Authority Model version or content hash that was approved - the approver identity - the approval timestamp - the template or policy version used to generate the approval view - the exact approved presentation view: - validated `display` object, or - validated A2UI interaction payload, or - a canonical AS-generated rendering derived from the Mission Authority Model This matters for: - audit replay - human-readable explainability - dispute resolution - regulated approval processes The architectural rule should be: - approvers approve a presentation artifact - the AS retains that approved presentation artifact as evidence - the AS must be able to prove that the retained presentation artifact was validated against the approved Mission Authority Model - the evidence record should carry a stable digest of the approved presentation artifact and a stable digest or version reference to the Mission Authority Model so that later auditors can verify that the rendered approval surface and the enforced authority model were the same approval event Without that evidence layer, "human approval" is harder to defend later because the system can show what authority was enforced but not what authority was represented to the approver at decision time. When approval is delegated to an external approval system, the external system must return enough information for the AS to preserve the same evidence standard. At minimum, it must return one of: - the final approved presentation artifact - a stable reference and integrity-protected hash of the approved presentation artifact - an AS-resolvable identifier that allows the AS to retrieve the exact approved presentation artifact later An external approval callback that returns only "approved" or "denied" without preserving the approved presentation artifact is insufficient for high-assurance or regulated approval flows. ## Enterprise Approval System Integration Many enterprises already have approval workflows: ServiceNow, Jira Service Management, enterprise HR systems, or custom approval portals. The Mission proposal and approval model should be designed to delegate to these systems rather than requiring a new approval UI. The approval endpoint should support an async delegation model: ```text POST /mission-proposals/{proposal_id}/approval -> 202 Accepted Location: /mission-proposals/{proposal_id} Body: { "approval_mode": "external", "external_system": "https://servicenow.enterprise.example/api/approval", "external_ticket_id": "REQ0012345", "callback_uri": "https://as.enterprise.example/mission-proposals/callback" } ``` The AS holds the proposal in `pending` state, the external system delivers its decision via callback or webhook, and the AS transitions the Mission accordingly. This allows Mission-Bound OAuth to sit above existing enterprise governance infrastructure rather than replacing it. For regulated enterprises, this is the adoption path: Mission proposals become work items in the existing approval system, and the AS acts on the approval output. **Callback authentication**: the approval callback endpoint (`https://as.enterprise.example/mission-proposals/callback`) MUST be authenticated. Unauthenticated callbacks that can transition a Mission from `pending` to `active` are a privilege escalation attack surface. Three acceptable models: 1. **Callback credential**: when the AS delegates approval to an external system, it issues a short-lived, audience-specific callback credential bound to the `proposal_id`. The external system presents this credential in the callback request. The AS validates it before accepting the approval decision. 2. **Webhook signing**: the external system signs callback payloads using a pre-registered key. The AS verifies the signature before processing. Key registration is part of the external system configuration at the AS. 3. **AS polling**: instead of receiving callbacks, the AS polls the external system for approval decisions. The AS authenticates to the external system using a registered client credential. No inbound callback endpoint is exposed. Deployments MUST implement at least one of these models. An unauthenticated callback endpoint MUST NOT be deployed. **Callback re-validation requirement**: authenticating the callback source is necessary but not sufficient. Between the time the AS delegated approval to an external system and the time the callback arrives, conditions may have changed: the proposal's approval window may have elapsed, the subject's organizational membership or authorization may have changed, or a hard policy deny that was not in effect at proposal time may now apply. The AS MUST re-run applicable policy checks at the time of callback receipt before transitioning the Mission to `active`. Specifically, the AS MUST re-validate: (1) the proposal has not expired, (2) the proposed mission type is still permitted for the requesting client, (3) no hard policy deny now applies to the subject or client. If any check fails, the AS MUST reject the callback with an appropriate error and MUST NOT activate the Mission, regardless of the callback credential's validity. The audit event for a rejected callback MUST record the reason for rejection. ## MCP Tool Metadata to Mission Proposal Mapping Many agent deployments use MCP as the tool and context plane. MCP tool schemas expose resource types, required parameters, and operation descriptions. A standard extraction of this metadata into Mission Proposal candidate authority would give agent platforms a concrete starting point without requiring bespoke proposal generation logic per tool. The mapping concept: ```json { "mcp_tool": { "name": "calendar_create_event", "description": "Creates a calendar event", "input_schema": { "calendar_id": "string", "title": "string", "attendees": ["string"], "start": "datetime", "end": "datetime" } }, "derived_authority_candidate": { "resource_type": "calendar.event", "operation_group": "calendar.schedule", "required_parameters": ["calendar_id"] } } ``` A standard extraction profile for MCP-to-Mission Proposal mapping would allow agent frameworks to auto-generate the candidate authority section of a Mission Proposal from the tools the agent has discovered, rather than requiring the agent to construct it from scratch. But the boundary has to stay explicit: - MCP tool names are not stable authorization identifiers - MCP schemas are not policy vocabulary - MCP metadata is proposal input, not authority The extraction step is therefore a translation into Mission vocabulary, not a direct reuse of tool metadata as policy semantics. That auto-generated candidate is then attenuated through templates and policy before becoming a real proposal. This is one of the most practical things the architecture can do to lower the entry cost for agent platform developers who are already using MCP without letting tool schemas silently become the authorization model. ## Handling Ambiguity When the prompt is incomplete or ambiguous, the architecture should bias toward narrower authority: - generate a narrower Mission Proposal - request clarification - request additional authority later through a new proposal Ambiguity should reduce scope rather than expand it. ## Progressive Mission Expansion Progressive expansion is an optional capability for deployments that need open-world adaptation after a Mission has started. It is not required for the minimum viable Mission-Bound OAuth profile. Simpler deployments may choose the stricter rule: if additional authority is needed, create a new Mission rather than expanding the existing one. When enabled, progressive expansion is the architecture's answer to the open-world bootstrap problem. Agents may discover additional authority requirements while executing a Mission. Rather than requiring all future resources to be enumerated up front, the model allows an agent to submit a constrained expansion proposal that references the current Mission. The key concept should be a **bounded authority envelope** rather than literal pre-enumeration of every future object. The parent Mission carries: - approved resource classes and selectors - approved operation families - approved relationship predicates - approved business-process and compliance bounds An expansion is allowed when the newly requested authority can be shown to fall **inside that approved envelope**, even if the exact runtime object or tool was not named earlier. That means: - a newly discovered email tool may be acceptable if `communication-with-approved-participants` is already inside the parent Mission envelope - a newly discovered CRM object may be acceptable if it matches the approved `accounts-owned-by-requesting-team` selector - a new operation outside the approved operation families still requires a fresh Mission proposal and approval cycle The envelope does not make expansion unconstrained. It simply moves the decision boundary from literal membership to policy-evaluable containment. This should be treated as a later profile for easier adoption: - baseline deployments can omit expansion entirely - deployments that need open-world adaptation can add expansion once their Mission templates, policy, and audit model are stable Containment should be evaluated across at least four dimensions: - **resource containment**: the requested resource type and selector fall within an approved resource class or selector family - **operation containment**: the requested action belongs to an approved operation group or operation family - **predicate containment**: the request does not introduce new relationship, process-state, compliance, or jurisdiction predicates outside the approved set - **risk containment**: the expansion does not exceed approved delegation depth, duration, checkpoint policy, or other execution bounds An expansion should be considered **inside the authority envelope** only when all four containment checks pass. If any one of them fails, the request is outside the approved envelope and requires a new Mission proposal or new approval step. ```json { "parent_mission_ref": "mr_7M9Qx2", "requested_extension": { "candidate_authority": { "resource_types": [ "email.message" ], "operation_groups": [ "email.send" ], "constraints": { "relationship": "participants-in-approved-meeting" } }, "display": { "title": "Send Meeting Invitation", "description": "Send an email to Dana confirming the scheduled meeting.", "actions": ["Send one email to Dana with meeting details"] } } } ``` This directly addresses the question "what happens when the agent discovers a tool it did not know about at startup?" The answer is not necessarily a new full authorization flow with the user. It is a scoped expansion request against the existing Mission, which the AS evaluates against the original approved authority envelope. If it fits inside that envelope, the expansion is approved. If it exceeds those boundaries, a new Mission proposal or a new approval step is required. This model keeps the user in control without requiring them to pre-enumerate every tool at consent time. ### Expansion Proposal Protocol Expansion proposals are submitted to `POST /missions/{mission_ref}/expand`. The endpoint requires a client credentials access token with scope `mission:expand`, issued to the same `client_id` that holds the active Mission. The `parent_mission_ref` in the body must match the `{mission_ref}` path parameter; mismatches MUST be rejected with HTTP 400. **Success response** (HTTP 202 Accepted): the expansion proposal is queued for evaluation. If the AS can evaluate envelope containment synchronously, it MAY return HTTP 200 with the expansion decision inline. ```json { "expansion_id": "exp_Hq37Wz", "state": "pending", "mission_ref": "mr_7M9Qx2", "status_uri": "https://as.example.com/missions/mr_7M9Qx2/expansions/exp_Hq37Wz" } ``` When the expansion is approved, the AS updates the Mission's compiled authority region (incrementing the Mission version counter) and emits a `mission.expanded` audit event. The client discovers approval by polling `status_uri`. The AS MAY also support a `callback_uri` in the expansion request body, following the same callback authentication requirements as the enterprise approval system integration. **Expansion does not produce a new `mission_ref`.** The existing Mission's compiled authority region is widened; the same `mission_ref` governs subsequent token exchanges. After an approved expansion, enforcement points that cached the prior Mission Authority Model version MUST re-fetch, as the version counter will have incremented. **If the requested extension exceeds the authority envelope**, the AS MUST return HTTP 422 with error `mission_expansion_outside_envelope` and a `mission_error_detail` object identifying which containment check failed (using the same `constraint_violated` vocabulary as `mission_authority_exceeded`). In this case the client must submit a new full Mission proposal and approval cycle. **Concurrency**: concurrent expansion proposals against the same Mission version MUST be serialized. An expansion evaluated against a prior version is rejected with HTTP 409 and error `mission_expansion_conflict`, requiring the client to re-fetch the current Mission state and re-evaluate before resubmitting. ## Headless and Service-to-Service Missions Not all agent workflows involve interactive users. Automation pipelines, scheduled reconciliation jobs, and system-level agents operate as service clients using client credentials (RFC 6749 Section 4.4) or pre-authorized grant flows with no consent screen. Mission governance still applies to these workflows; the approval model is different. **Subject binding for headless missions**: the proposal schema requires a `subject` field. For headless service-to-service missions, the subject is the service principal on whose behalf the automation runs, not an interactive user. Two cases apply: - **Client-as-subject**: the orchestration layer is itself the subject. The `subject.sub` is the client's registered service identity and `subject.iss` is the AS or IdP that issued the service identity. This is the appropriate model when the agent is acting on behalf of a system or process rather than a human. - **Service-identity subject**: the client is acting on behalf of a distinct service identity (e.g., a batch job identity registered in a service account directory). `subject.sub` and `subject.iss` refer to that identity, and the AS validates the orchestration layer's authority to propose Missions on behalf of that subject via client registration metadata. If `subject` is omitted from a headless mission proposal, the AS MUST treat the `client_id` as both client and subject. Deployments that require explicit subject tracking for audit purposes SHOULD require the `subject` field even for headless missions. For headless missions, the architecture provides two models: **Policy-auto-approved missions**: at Mission proposal time, the AS evaluates the request against a registered policy for the client and mission type. If the client is registered for the requested mission type and the policy permits it, the AS activates the Mission immediately at creation without an interactive consent step. The audit trail records the policy evaluation as the approval event. This is appropriate for well-defined, low-risk automated workflows where a security team has pre-vetted the mission type for specific client identities. **Pre-provisioned mission types (standing mission authorizations)**: a security team or administrator registers approved mission types for specific service clients at provisioning time, analogous to client registration for OAuth scopes. At runtime, a service client activates a Mission of a pre-approved type by calling `POST /missions/activate` with the following request body: ```json { "mission_type": "urn:example.com:mission:nightly-reconciliation", "client_id": "reconciliation-service" } ``` The endpoint requires a client credentials access token with scope `mission:activate`, issued to the requesting `client_id`. The AS validates that the `mission_type` is in the client's `mission_types` registration with `approval_mode: pre_provisioned` and activates the Mission immediately. The response is HTTP 201 Created with the same body format as an approved proposal response, including `mission_ref` and `mission_uri`. No runtime proposal or approval cycle is required. The pre-provisioned type defines the compiled authority region, delegation bounds, lifecycle constraints, and business event terminal conditions that apply to every instance of that mission type for that client. The AS MUST record the activation as an audit event (`mission.created`) with the registration record as the authorization evidence. Lifecycle governance applies identically to headless missions. Business event termination, suspension, delegation bounds, and the audit trail all apply. The only difference from interactive missions is that initial activation is delegated to policy evaluation or pre-registration rather than a user consent flow. A service client that has not been registered for a mission type cannot request one regardless of its client credentials. The registration boundary for headless clients is the same provisioning-time authority check that client registration provides for interactive clients. ## Mission Authoring and Policy Authoring One thing this architecture needs to make clearer is the difference between **mission authoring** and **policy authoring**. Mission authoring is about describing a proposed unit of authority for a specific Mission instance: - what the agent is trying to do - on whose behalf it is acting - what authority region appears necessary - what parameters and time bounds apply Policy authoring is about defining the standing rules that govern whether a proposed Mission is acceptable: - which mission templates are allowed - which authority regions, selectors, and operation groups are valid for a purpose - when step-up or admin approval is required - how delegation depth is bounded - what environmental conditions change the decision In other words: - a **Mission** is an instance - **policy** is what decides whether the instance is allowed, and in what form That distinction matters operationally. It means an enterprise can let application teams define mission templates and Mission parameters without also giving them the ability to redefine global authorization policy. ## Prompting as a Policy Authoring Front-End One practical question for enterprises is whether prompting and intent systems can help close the policy-authoring gap. The answer is yes, but only if they are treated as an authoring front-end rather than as the governance authority. Prompting and intent are useful for: - drafting Mission templates from business-language descriptions - proposing operation groups, selectors, and constraint candidates - translating messy enterprise process language into structured Mission vocabulary - helping platform and security teams bootstrap a first policy model in domains where raw resource/action inventories are too complex to author directly A useful mental model is: - prompts and intent act as a semantic compiler front-end - Mission templates and authority models are the compiled artifacts - policy review and approval remain the governance checkpoint In enterprise terms, that means a team might start with a policy prompt such as: > Sales assistants may prepare renewal packages for accounts owned by their team, only during active renewal stages, only in EU-hosted systems, and only for the current quarter. The system can then generate a draft template containing: - a purpose class - operation groups - resource selector families - relationship predicates - process-state predicates - compliance constraints - lifecycle defaults That draft still needs human and policy-system review before it becomes an approved Mission template or organization policy binding. This distinction matters because prompting can make policy authoring more legible, but it does not make policy governance optional. The practical enterprise pattern is: 1. prompting and intent generate candidate templates or authority-model fragments 2. security and platform teams review and normalize them 3. approved templates become reusable Mission authoring inputs 4. runtime prompts only instantiate within those approved templates and authority envelopes That is how prompting can help solve the enterprise policy-authoring gap without letting runtime language generation silently become the authorization system. ## Mission Templates, Profiles, and Authoring Boundaries In practice, large deployments will need more than raw per-request proposal JSON. They will likely need: - reusable mission templates - purpose catalogs - operation groups - resource-type definitions - approval profiles - organization-level policy bindings In practice, at least three authoring layers are needed: - **runtime mission proposals** created by clients or agents - **mission templates** managed by platform or application teams - **authorization policy** managed by security or governance teams That separation gives a path to scale. Without it, every Mission becomes a bespoke authority object and policy quickly becomes unmanageable. ## Beyond Allowlists: Constraint-Driven Mission Authoring One of the biggest open issues in this architecture is that explicit allowlists do not scale far enough for real deployments. It is easy to model a Mission as: - allowed resource regions - allowed operation groups - max duration - max delegation depth That is useful, but it is not enough. Real authorization decisions often depend on constraints such as: - jurisdiction or data residency - compliance regime - business process stage - relationship to the subject or record - organizational role - customer or tenant boundary - risk posture - time, location, or execution environment In many cases, those constraints are more important than a literal allowlist of resource names. A scheduling assistant may be allowed to create events, but not for executive calendars, not for regulated accounts, not outside a region, and not outside an approved business process. That suggests the Mission model needs to support **constraint-driven authority**, not just explicit allowlists. ## Missions as Guardrails for Open-World Agents This is where Missions become more than a label. For open-world agents, the problem is not just "what exact API calls are pre-approved?" It is "what bounded space is the agent allowed to explore while still remaining safe?" Mission-Bound OAuth can help by making the Mission the **guardrail object** for open-world execution: - the agent may discover tools dynamically - the agent may discover new candidate resources at runtime - the agent may plan adaptively - but every derivation still has to stay inside Mission constraints The Mission does not need to enumerate every future action up front. Instead, it defines a bounded authority region within which planning and execution are allowed to adapt. Progressive expansion provides the escape valve for genuinely novel requirements that appear at runtime. ## Why This Matters for FGA Fine-grained authorization (FGA) has often been hard to apply to agent missions not because FGA models are weak, but because the mapping problem is too large: - too many resources - too many operations - too much runtime ambiguity - too little structure around agent intent Missions can help unblock that by introducing a bounded intermediate layer between open-ended intent and concrete policy evaluation. Instead of asking policy systems to solve arbitrary agent behavior directly, the system can: 1. interpret intent into a Mission Proposal 2. constrain it through templates, policy, and approval 3. compile it into an evaluable authority region 4. use FGA, AuthZEN, or policy engines to answer specific runtime questions inside that region That makes fine-grained authorization more tractable for open-world agents because the Mission narrows the search space and carries the governing context forward. ## Deployment Pattern Examples The easiest way to understand the FGA and policy gap is to look at a few existing deployment patterns and ask what the Mission contributes in each one. ### Pattern 1: Gateway Enforcement with FGA Behind It **Example**: a procurement assistant can create or update vendor onboarding records for vendors in procurement cycle `P-4421`. Without Missions: - OAuth gets the agent a token for the procurement APIs - FGA can answer object-level questions such as "may this team update vendor `V-8821`?" - but nothing cleanly carries the approved purpose, procurement-cycle boundary, jurisdiction limits, or terminal conditions across the run With Missions: - the Mission bounds the authority region to vendor-onboarding actions in procurement cycle `P-4421` - the gateway uses the projected Mission reference to fetch or cache Mission context - the gateway asks the PDP or FGA layer whether the requested vendor record is inside the approved selectors and relationships - when the procurement cycle closes, a business event terminates the Mission and the gateway stops forwarding further writes What the Mission adds is not another object-level policy decision. It adds the bounded authority context that tells the gateway and FGA system which object-level questions are even legitimate to ask. ### Pattern 2: Resource Server with Local Policy **Example**: a CRM API already has local authorization logic and ownership checks, but now an agent is asked to "prepare renewal notes for accounts my team owns this quarter." Without Missions: - the RS sees a broadly scoped token such as `crm.write` - the RS can apply its normal local policy - but it has no standard way to know whether this write is part of the approved renewal mission, whether the mission is still active, or whether the write falls inside the approved business process and time bounds With Missions: - the token carries a projected Mission reference - the RS either consumes Mission-derived claims or calls the Mission introspection profile - local policy continues to decide object-level access, but now it can combine that with Mission state, Mission purpose, and Mission constraints - the RS can deny writes when the Mission is suspended, expired, or outside the approved renewal process even if ordinary OAuth scope would otherwise allow the call What the Mission adds is a portable governance layer above existing RS-local authorization logic. ### Pattern 3: FGA as the Runtime Decision Engine **Example**: a support assistant is asked to update tickets related to incident `INC-4421`. Without Missions: - FGA can model relationships between users, teams, incidents, and tickets - but the agent may discover relevant tickets, notes, and linked records dynamically at runtime - the policy problem becomes open-ended because the system has no approved authority envelope for what counts as "part of this incident mission" With Missions: - the Mission expresses the approved authority envelope: - ticket and note resource types - incident-linked selectors - allowed operation groups such as `ticket.update` and `note.append` - process-state predicates such as "incident still active" - FGA answers the narrower runtime questions: - is ticket `T-5512` linked to incident `INC-4421`? - is the current team allowed to update it? - is the requested action inside the approved operation family? What the Mission adds is the intermediate layer that makes open-world FGA queries tractable for agents rather than arbitrary. ### Pattern 4: Mixed Estate with Mostly Legacy Resource Servers **Example**: an enterprise has many legacy internal APIs behind a gateway and cannot make every backend Mission-aware. Without Missions: - teams either issue broad workflow tokens or build ad hoc gateway metadata - revocation and termination are mostly tied to token lifetime - audit correlation across the mission is inconsistent With Missions: - the AS becomes the authoritative Mission lifecycle control point - token exchange gates downstream token issuance on Mission state - the gateway can enforce Mission-aware checks for high-value operations - legacy backends continue to validate normal tokens without understanding the full Mission model What the Mission adds is a practical migration path: stronger authority governance at the AS and gateway without requiring every RS to adopt a new model on day one. Across all four patterns, the recurring gap is the same: - OAuth provides token transport and audience binding - FGA, AuthZEN, and local policy provide object-level decisions - the Mission provides the bounded delegated authority context that makes those decisions coherent over time # Deployment and Operational Model ## Cross-Domain Mission Authority This section is included for architectural completeness, but it should be treated as a later profile rather than a near-term core standardization target. The single-domain and same-trust-boundary story is the part of the architecture that is ready to be pressure-tested first. Cross-domain Mission transport, trust establishment, projection rules, and revocation propagation are all materially less settled and should not block the core Mission-Bound OAuth story. Agent missions do not stay within a single authorization domain. An agent may authenticate at an enterprise Identity Provider (IdP), execute steps against internal APIs, and then need to reach APIs governed by a partner organization or SaaS provider. The cross-domain case has two distinct problems: **Same-IdP trust domain**: multiple resource servers share a common Identity Provider. In this case, a projected Mission-bearing assertion from the originating trust domain can act as the trust anchor for downstream token exchange, with the IdP validating Mission scope before issuing assertions for each Resource AS. This is the Identity Assertion Authorization Grant (ID-JAG) pattern and it works well within an enterprise where all resource servers federate to the same IdP. **Different-IdP trust domain**: the receiving AS has no trust relationship with the issuing AS. The architecture needs a portable Mission assertion that the receiving AS can validate independently. For the cross-domain case, the Mission reference needs a portable form: - a signed Mission assertion (analogous to how ID-JAG packages an authentication event for cross-domain use) carries the mission purpose, constraints, and subject identity in a verifiable artifact - the receiving AS validates the assertion against the issuing AS's published keys - the receiving AS applies its own policy to determine whether the asserted mission scope is acceptable within its domain The normative definition of this assertion format, filtering rules for which mission claims cross a trust boundary, and the federation trust mechanism connecting the two ASes are the open problems for the cross-domain profile. OpenID Federation is the natural trust infrastructure for the key discovery and trust chain validation. SSF/CAEP is the natural mechanism for propagating mission revocation across domains once the Mission terminates at the issuing AS. The privacy concern applies here directly: subject identifiers in cross-domain Mission assertions may need pairwise forms, and mission semantics should be projected to only what the receiving domain needs for enforcement. A receiving AS should not receive the full compiled authority region from the issuing AS, only the subset relevant to the resources it governs. ### Cross-Domain Mission Assertion: Candidate Claim Structure A Mission assertion crossing a trust boundary is a signed JWT (JWS) with the following candidate claim set: ```json { "iss": "https://as.example.com", "sub": "user-123", "sub_profile": "user", "aud": "https://partner-as.example.org/token", "act": { "sub": "assistant-agent", "sub_profile": "ai_agent" }, "delegation_chain": [ { "sub": "assistant-agent", "sub_profile": "ai_agent" } ], "mission_ref": "mr_7M9Qx2", "purpose": "urn:example.com:mission:schedule-meeting", "mission_exp": 1773072000, "projected_authority": { "allowed_operations": ["calendar.schedule"], "constraints": { "region": "EU" } }, "exp": 1773072300, "jti": "a8f3c91b-4d2e-4f7a-b5e6-9c0d1f2e3a4b" } ``` Key projection rules: - `sub` and `sub_profile` identify the user on whose behalf authority is asserted; pairwise subject identifiers SHOULD be used when crossing domains without an established federation agreement - `mission_ref` is projected as-is or as a pairwise handle; the receiving AS maps it back to a locally-issued `mission_ref` for tokens it issues - `projected_authority` is a filtered subset of the compiled authority region relevant to the receiving domain's resources; the issuing AS MUST NOT include authority elements outside the receiving domain's registered resource types - `mission_exp` is the Mission's expiry at the issuing AS; the receiving AS MUST issue tokens that do not outlive this expiry - The assertion's own `exp` SHOULD be short (e.g., 5 minutes) to limit replay; `mission_exp` governs the Mission's actual authority window - OpenID Federation is the trust infrastructure for key discovery and trust chain validation between the two ASes ## Continuous Evaluation Checkpoint Model Continuous evaluation does not mean a synchronous round-trip to the AS on every API call. That model does not scale at production volumes and creates a single point of failure when the AS is unavailable. The recommended model is hybrid: **Synchronous Mission check** before: - token exchange for any new resource or delegation hop - high-value or irreversible actions (defined by the Mission's risk classification) - any action that modifies authority scope or delegation state **Asynchronous signal-based check** for: - high-volume, low-risk, reversible operations where the Mission is assumed valid until a termination signal arrives The AS pushes Mission state change events via the Shared Signals Framework (SSF) and Continuous Access Evaluation Protocol (CAEP). Enforcement points subscribe to these events and act on them. When a termination event fires, enforcement points block further execution at the next checkpoint. Which action type falls into which category should be policy-defined at Mission approval time, not left to ad hoc runtime behavior. A Mission that does not specify its evaluation checkpoint policy has not fully specified its governance model. The revocation lag window between a termination signal and its enforcement at all checkpoints must also be policy-defined. Tighter lag reduces exposure but increases availability dependency. That tradeoff should be explicit. ## Business Event to Mission Termination Business events are the terminal conditions that make the architecture real. The expired-mandate scenario (an agent still pulling sensitive data after its governing business event has closed) is not solved by better token expiry. It is solved by the procurement system publishing a "program closed" event that flows into the Mission layer and terminates the Mission independently of clock state. The integration model: 1. At Mission approval, terminal conditions are declared: "this Mission terminates when event type `procurement.program.closed` is received for program `PRG-4421`" 2. Business systems publish state change events to an SSF event stream 3. A Mission evaluation service subscribes to that stream and evaluates incoming events against declared terminal conditions 4. When a match fires, the Mission transitions to `completed` or `revoked` and the AS stops issuing derivatives 5. A CAEP `mission-terminated` event propagates to subscribers so enforcement points can halt in-flight execution For conditions that cannot be instrumented against machine-observable events, the Mission falls back to hard expiry. Even in the hard-expiry fallback, the Mission carries what tokens alone cannot: an authoritative mission record the rest of the security stack can query, a cascade revocation chain, and an audit trail attributing execution to a specific delegated purpose. As instrumentation improves, the condition model grows with it without requiring architectural changes. **Event source authentication**: event sources that can trigger Mission termination are high-value attack targets. An adversary who can publish a fabricated terminal event for a known program identifier can terminate Missions they should not touch. Event sources delivering terminal conditions MUST be pre-registered at the AS as part of Mission approval metadata. Registration includes: - the event source identifier - the event types the source is authorized to publish - the SSF transmitter authentication credentials (as defined in SSF 1.0) used to authenticate the source's event stream The AS MUST validate that an incoming terminal event originates from a pre-registered, authenticated transmitter before transitioning a Mission. Unauthenticated terminal events MUST be discarded. **Replay protection**: terminal events are high-value single-fire triggers. The AS MUST implement replay protection for terminal events: - Each event MUST carry a unique event identifier (`jti` or equivalent) and a timestamp. - The AS MUST maintain a short-lived record of processed event identifiers (at minimum, for the duration of the event stream's configured delivery window). - An event with a duplicate identifier or a timestamp outside the AS's configured acceptance window MUST be discarded. - Event timestamps MUST be monotonically non-decreasing within a single event stream; out-of-order events that predate the most recently processed event for the same program identifier MUST be rejected. ## Transaction Token Integration OAuth Transaction Tokens (Txn-Tokens, [draft-ietf-oauth-transaction-tokens](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-transaction-tokens-08)) are designed to propagate trusted workload identity and call context across microservice boundaries inside a single enterprise. They complement Mission-Bound OAuth by providing the in-network context propagation layer that mission-bearing access tokens are not designed for. The architectural relationship: - **Mission-bearing access tokens** govern delegated authority at the OAuth boundary: what the agent is authorized to do, under which Mission, on whose behalf. They cross trust boundaries and are validated by RSes using standard JWT validation. - **Txn-Tokens** propagate workload context within a trusted service mesh: who called whom, with what initiating token, and for what transaction. They are typically scoped to a single enterprise network boundary. A Txn-Token issued inside an enterprise may carry a `mission_ref` claim linking the in-flight transaction to its governing Mission. This allows internal services that do not receive the original mission-bearing access token to still have access to the Mission reference for audit, policy evaluation, or context propagation. The integration model: 1. An external or orchestration-layer request arrives at the edge with a mission-bearing access token containing `mission_ref` 2. The edge service creates a Txn-Token for the internal call chain, carrying workload identity, the initiating token reference, and the `mission_ref` from the incoming access token 3. Internal microservices that receive only the Txn-Token can resolve Mission state via the AS introspection endpoint using the Mission introspection profile and the `mission_ref` the Txn-Token carries 4. Audit records from internal services carry `mission_ref`, linking all steps in the call chain to the governing Mission This is the correct model for trusted-network deployments where not every internal service hop involves a full OAuth token exchange. The Txn-Token carries the Mission reference as context, not as authority. Authority for each internal service remains governed by its own policy decision, informed by the Mission context the Txn-Token provides. The `mission_ref` claim in a Txn-Token should be treated as informational context, not as a delegated authority grant. The Txn-Token model does not replace Mission lifecycle enforcement: services that need to enforce Mission state must still check it via introspection, not by trusting the `mission_ref` claim alone. Deployments MUST NOT silently downgrade from Mission-aware enforcement to token-only enforcement because an introspection or authority-model retrieval path is unavailable. Any fallback to weaker enforcement semantics must be an explicit deployment policy decision with documented risk, not an automatic runtime behavior. ## Policy Integration Mission-Bound OAuth is not trying to replace policy engines. Its role is to define mission authority semantics and how they integrate with OAuth. Constraint evaluation may be delegated to a policy system such as the AuthZEN Authorization API. In that model: - Mission-Bound OAuth defines the lifecycle and authority object - AuthZEN evaluates whether a specific action on a specific resource is allowed under current policy That separation matters because it keeps the architecture focused on authority semantics and processing points rather than on a single PDP technology. ## Policy Conflict Precedence IAM systems need a deterministic answer when multiple control sources disagree. The precedence model should be: 1. issuer and tenant boundary checks 2. Mission lifecycle state 3. client registration and permitted Mission classes 4. hard policy denies 5. Mission Authority Model authority region 6. runtime relationship and environmental predicates 7. local RS or gateway policy narrowing This means: - if the Mission is revoked, everything stops regardless of lower-layer policy - if registration does not permit the Mission class, approval cannot create it - if hard policy denies a resource or action, user approval cannot override it - if the Mission Authority Model allows a region but runtime predicates fail, the request is denied without changing the Mission - RS and gateway policy may narrow or block execution further, but should not widen authority beyond the Mission ## How AuthZEN Fits OpenID AuthZEN fits naturally into this architecture as the **decision interface** between policy enforcement points and policy decision points. It does not replace [Mission-Bound OAuth](#architecture-overview), and Mission-Bound OAuth does not replace it. The clean division is: - Mission-Bound OAuth defines the Mission authority object, lifecycle, delegation semantics, and OAuth processing checkpoints - AuthZEN provides a way for an AS, gateway, or resource server acting as a PEP to ask whether a specific action on a specific resource is allowed under current policy In that model: - the AS is often a PEP at issuance and token exchange time - a gateway may be a PEP at request time - an RS may also be a PEP when it has sufficient context - the PDP evaluates mission-derived context, actor context, resource context, and environmental context That means the architecture can support both: - **embedded decisioning**, where the AS evaluates policy internally - **externalized decisioning**, where the AS or gateway calls an AuthZEN-compatible PDP In more advanced deployments, the Mission may need to contribute not just literal attributes but a compiled set of constraints, selectors, and relationship predicates that the PDP can evaluate at runtime. The compiled authority example from the Authority Compilation Boundary section is the expected input to an AuthZEN-style query. ## Mission Evaluation Input Model To make the open-world model credible, the architecture needs a clearer statement of what a Mission-aware runtime decision consumes. A Mission-aware decision input should include at least: - **actor context**: client, user, delegated actor, authentication strength - **mission context**: mission identifier, state, purpose, expiry, delegation state - **authority context**: compiled selectors, operation groups, relationship predicates, compliance constraints - **resource context**: target resource type, instance, container, attributes - **action context**: requested operation, operation group, execution mode - **environment context**: time, region, network, tenant, process stage A sketch: ```json { "actor": { "client_id": "assistant-agent", "subject": "user-123", "delegation_depth": 0 }, "mission": { "mission_ref": "mr_7M9Qx2", "state": "active", "purpose": "urn:example.com:mission:schedule-meeting", "exp": 1773075600 }, "authority": { "operation_groups": [ "calendar.schedule", "crm.record_activity" ], "selectors": [ "calendar:user-manageable", "crm:accounts-owned-by-requesting-team" ], "constraints": { "region": "EU", "business_process": "meeting-followup" } }, "resource": { "type": "crm.account_note", "account_id": "acct_123" }, "action": { "name": "create", "group": "crm.record_activity" }, "environment": { "region": "EU", "workflow_stage": "post-meeting" } } ``` ## Explainability and Administrative Visibility IAM governance is not complete if a Mission can be denied, attenuated, or suspended without intelligible reasons. At minimum, the model should support two explanation views: - **machine-readable** reasons for clients and agents - **human-readable** reasons for administrators, approvers, and auditors Machine-readable reasons should identify: - which Mission was evaluated - which checkpoint failed - whether the failure is temporary or terminal - which policy or predicate class caused the denial Human-readable reasons should identify: - the attempted Mission action - the governing policy or lifecycle rule - who or what caused the state change - what remediation path exists, if any This is particularly important for: - mission proposal denial - mission attenuation - mission suspension - token exchange denial under `mission_authority_exceeded` - cross-domain assertion rejection ## How MCP Fits The document also needs to say how MCP fits, because many agent deployments now use it as the tool and context plane. MCP is not an authority protocol. It helps agents discover tools, exchange structured context, and invoke capabilities. In this architecture, MCP sits **above** Mission-Bound OAuth. The clean relationship is: - MCP exposes tools, schemas, and invocation surfaces to the agent - the agent uses MCP to understand what tools exist and what inputs they need - Mission-Bound OAuth determines whether the agent is actually authorized to use those tools in the current Mission - OAuth tokens and token exchange provide the concrete access artifacts for the underlying APIs MCP can be relevant in at least three places: - **tool discovery**: which tools and operations are even available to plan against - **proposal construction**: mapping tool schemas and operation metadata into Mission Proposal candidates - **runtime enforcement hints**: attaching operation metadata that helps the AS, gateway, or PDP map a tool call to resource/action policy The architectural boundary should be explicit: MCP is the tool-interaction layer; Mission-Bound OAuth is the delegated authority layer. ## Discovery and Metadata Any eventual spec work will need discovery metadata so clients can determine whether an AS supports Mission-Bound OAuth. Likely areas for discovery include: - mission proposal endpoint support - approval endpoint support - supported Mission reference mechanisms - token exchange behavior - delegation capabilities - policy integration hints - mission introspection endpoint For the umbrella architecture, it is useful to distinguish: - OAuth AS metadata for core protocol support - mission management metadata for proposal, approval, and template features - resource metadata for mission-aware enforcement capabilities # Security Considerations ## Threat Model The threat model is aimed at reducing: - **ghost execution**: agents acting without approved Mission authority - **privilege creep**: Missions accumulating more authority than was approved - **uncontrolled delegation**: one actor silently widening a chain of authority - **token replay**: stolen artifacts being reused outside intended conditions - **actor substitution**: a different actor than the one the Mission approved presenting mission-bearing tokens at exchange time, either through token theft, confused-deputy exploitation, or forged actor chain claims Mission-Bound OAuth does not eliminate normal OAuth threats. It adds controls for mission continuity and bounded authority on top of the existing security baseline. ## Security Properties to Preserve For the proposal to be credible, it should preserve the following: - access tokens remain audience-bound - mission state is authoritative at the AS - downstream issuance is denied when mission state is invalid - delegation is explicit and bounded, represented via `act` (current actor) and `delegation_chain` (full ordered history) - approval and execution remain separate trust steps - policy decisions are explainable and auditable - mission audit events are signed and independently verifiable ## AS as Critical Security Infrastructure The AS holds authoritative Mission state and Mission Authority Model artifacts for every active agent execution it governs. Compromise of the AS or its Mission store is compromise of execution governance across every Mission it controls. Hardening requirements mirror those of authorization servers generally. Mission Authority Model artifacts must be signed so enforcement points can validate them without a live callback. Fail-closed behavior is required: an unavailable AS halts token exchange and Mission introspection rather than defaulting to open. Every Mission issuance, amendment, and revocation is a first-class security event with a full audit record. ## Sender Constraining Requirements Sender-constraining using DPoP (RFC 9449) or mTLS (RFC 8705) is a baseline expectation, not optional hardening. A deployment that accepts unsigned bearer mission-bearing tokens at token exchange is accepting meaningful replay risk against a durable authority chain. At least one deployment profile should treat sender-constraining as a core assumption that applies to both primary mission-bound access tokens and any tokens produced by mission-scoped exchange. ## Display Object Validation Template-driven display validation is a security requirement, not a UX convenience. An orchestration layer that supplies a `display` object claiming a benign action while the compiled authority permits something broader has created a social engineering attack surface that defeats the human-in-the-loop guarantee. The AS must validate or regenerate the display object from the compiled authority before presenting it to an approver. A display object that cannot be verified against the compiled authority region must be rejected or overwritten by the AS. ## Concurrency and Atomicity Requirements Mission-Bound OAuth places the AS as the authoritative state owner for Mission lifecycle, delegation depth, and compiled authority. Under concurrent load, several AS operations must be atomic to preserve correctness guarantees. **Mission lifecycle state transitions** (Issue 7.2): the AS MUST evaluate Mission lifecycle state and issue a token within the same atomic operation. A Mission suspension event and a concurrent token exchange request MUST be serialized. The AS MUST NOT issue a token for a Mission that is in `suspended`, `revoked`, `completed`, or `expired` state at the moment of issuance, regardless of the order in which the suspension and exchange requests arrived. **Delegation depth enforcement** (Issue 7.3): `current_depth` increments MUST be performed atomically using a compare-and-increment operation. The AS MUST reject any token exchange that would result in `current_depth >= max_depth` at the time the increment is committed, even if the exchange request was received when `current_depth` appeared valid. Concurrent delegation exchanges MUST be serialized per Mission. **Concurrent expansion proposals** (Issue 7.1): expansion proposals submitted concurrently against the same parent Mission MUST be serialized using the Mission's version counter. The AS increments the version counter on each accepted expansion. A concurrent expansion proposal that was evaluated against a prior version MUST be rejected with a concurrency error, requiring the submitter to re-evaluate against the updated Mission. This prevents two independently-valid expansions from collectively exceeding the authority envelope. **CAEP-triggered Mission suspension** (Issue 7.4): when the AS receives a CAEP `session_revoked` event for a user session, it must suspend all active Missions for that session. This suspension MUST be treated as a lifecycle state transition and MUST be serialized with any concurrent token exchange requests against the affected Missions. The AS MUST NOT issue a token for a Mission that is simultaneously being suspended by an incoming CAEP event. The implementation model is the same as for lifecycle transitions: the CAEP handler acquires the same per-Mission lock before transitioning state, and any concurrent exchange request that arrives during suspension processing receives `mission_suspended`. **Implementation guidance**: optimistic locking with a version counter on the Mission record is the recommended implementation pattern. The AS should expose the Mission version in `GET /missions/{mission_ref}` responses so clients can detect version changes between reads and submissions. # Privacy Considerations ## Privacy and Linkability Mission-Bound OAuth creates a risk of durable mission correlation across APIs and domains if Mission references and attributes are exposed too broadly. The privacy model should therefore assume: - the projected Mission reference is opaque and unguessable - Mission-derived claims are minimized per audience - resource servers receive only the Mission data needed for enforcement - introspection and token exchange avoid exposing Mission semantics unnecessarily - cross-resource correlation is limited where possible by deployment policy or identifier strategy - subject identifiers in cross-domain Mission assertions should use pairwise forms where appropriate This has to be explicit, otherwise the design looks like a powerful coordination primitive but also a powerful tracking primitive. **Per-audience Mission references** address the correlation concern more directly. A single visible Mission handle across multiple resource servers creates a cross-service tracking handle even when the identifier reveals no Mission semantics. RS-A and RS-B can correlate all workflow traffic using the shared handle without any explicit data-sharing agreement. Three deployment approaches are available, each with different tradeoffs: 1. **Single handle with audience-isolation policy**: use one projected Mission reference but control which resource servers receive it in their access tokens via audience-specific claim filtering at the AS. Resource servers that do not need cross-Mission correlation receive tokens without the Mission reference claim. 2. **Per-audience Mission references**: the AS maintains one internal Mission record and maps it to per-audience handles in issued tokens, analogous to pairwise subject identifiers in OpenID Connect. Each resource server receives a different handle that the AS maps back to the internal Mission for introspection and revocation. Cross-RS correlation is possible only through the AS, not by comparing token claims directly. 3. **Claim-free enforcement via introspection**: the Mission reference claim is omitted from audience-specific access tokens entirely. Resource servers that need Mission state use the introspection profile with a session-scoped reference that does not expose the Mission correlation handle in tokens. Deployments that require cross-RS audit correlation (compliance, regulated workflows) may use option 1 or 2. Deployments where cross-RS linkability is a privacy concern should prefer option 2 or 3. The architecture does not mandate a single approach, but a deployment profile should specify which model it uses and what the privacy implications are. ## Retention and Governance Enterprise IAM deployments will also care about retention classes for Mission artifacts. Retention will likely differ for: - Mission Proposals, including denied proposals - Approved Missions - Mission Authority Model representations - Mission audit events - cross-domain Mission assertions - introspection records or access logs A sensible default model is: - Mission Proposals: retained for governance and forensic review, especially when denied or attenuated - Approved Missions: retained for the duration of their lifecycle plus policy-defined audit retention - Mission Authority Model representations: retained at least as long as needed for replayable audit and explainability - Mission assertions: retained according to federation and compliance policy, usually shorter than the Mission itself The main architectural point is that Mission governance creates artifacts with different sensitivity and retention needs. Treating them all as generic auth logs would be an enterprise design mistake. # Practical Limits and Realistic Claim This architecture is intentionally ambitious. It is also easy to be too optimistic about where the hard parts really are. The protocol surfaces are only one part of the problem. Real deployments fail for data, governance, operational, and organizational reasons long before they fail for lack of a token claim. ## Policy Authoring May Be Harder Than the Protocol The architecture assumes enterprises can define: - Mission templates - operation groups - authority envelopes - relationship predicates - approval policies - business event termination conditions In practice, many organizations struggle to maintain even scope inventories and role mappings. Mission-Bound OAuth will fail if policy authoring becomes too complex for platform teams to manage coherently. ## Relationship and Business Data May Be Wrong Much of the promise of Mission-bound enforcement depends on external data being accurate: - who owns an account - which calendars a user can manage - what tenant a record belongs to - which process stage a task is in - whether a compliance boundary applies If those sources are stale or inconsistent, the Mission will be evaluated incorrectly. The architecture should assume imperfect upstream systems and treat some predicates as high-assurance only when backed by reliable sources of record. ## Open-World Envelopes Are Hard to Tune The bounded authority envelope is the right model, but tuning it is difficult. - if the envelope is too narrow, agents fail constantly and users are pushed into repeated re-approval - if the envelope is too broad, the system recreates over-delegation with more structure but not more safety The practical challenge is not just defining the envelope format. It is defining envelopes that are operationally usable and still meaningfully bounded. ## Approval UX May Collapse into Rubber Stamping If Mission approvals are too frequent, too technical, or too hard to understand, users and administrators will approve them mechanically. At that point, the architecture still has lifecycle and audit value, but the human-governance story becomes much weaker than the document implies. Approval is only a security control if: - the approver understands what is being approved - the approval frequency is tolerable - the attenuation path is usable in practice ## The Authorization Server May Become a Bottleneck Mission-Bound OAuth places more responsibility on the AS: - Mission storage - lifecycle transitions - approval integration - token exchange enforcement - compiled authority evaluation or policy calls - introspection That increases both scaling pressure and blast radius. If the AS or its dependent policy systems become slow or unavailable, mission execution may stall. A practical deployment needs a clear resilience model, not just a correctness model. ## Cross-Domain Adoption Will Likely Be Slow The single-domain and same-trust-domain cases are the most realistic near-term targets. Cross-domain Mission assertions require: - trust establishment - constrained claim projection - policy compatibility between issuers - revocation propagation - privacy-safe subject handling That is possible, but not likely to arrive quickly across a broad SaaS ecosystem. The architecture should be practical about this and avoid over-claiming cross-domain near-term interoperability. ## Resource and Operation Normalization May Never Fully Converge The document assumes useful structure for: - resource types - selectors - operation groups - relationship predicates That structure is necessary, but real ecosystems are heterogeneous. Different vendors will name and group actions differently. The practical goal is not perfect semantic portability. It is enough structure to make Mission evaluation tractable within a deployment and partially interoperable across similar deployments. ## Agents Can Still Route Around Governance Mission governance only helps if execution actually goes through Mission-aware issuance and exchange paths. In the real world, agents and automation systems often have: - legacy service credentials - direct backend access paths - side-channel APIs - cached tokens or unmanaged connectors If those paths remain, an agent may still act outside Mission governance. This architecture is strongest when paired with credential minimization and a policy that delegated machine access must flow through Mission-aware infrastructure. ## Revocation and Termination Are Not Instant The architecture improves lifecycle control, but it does not eliminate lag: - already-issued short-lived access tokens may remain usable until expiry - event propagation may be delayed - gateways may not all receive updates at the same time - introspection may be cached or temporarily unavailable This should be described as a bounded-exposure model, not as perfect real-time stop semantics. ## Compilation May Become Proprietary One of the strongest ideas in the document is the Mission Authority Model as the boundary between open-ended intent and enforceable authority. That is also where vendor-specific divergence is most likely. If every implementation has a radically different compiled authority model, interoperability may collapse at the most important architectural layer. The practical response is to standardize interfaces and processing checkpoints first, and be cautious about over-standardizing the compiled representation too early. ## Practical Claim The realistic claim for Mission-Bound OAuth is not: > this architecture solves open-world agent authorization. The realistic claim is: > this architecture gives IAM systems a governed authority object that makes bounded delegation, lifecycle control, auditability, and policy-backed token derivation materially better than token-only OAuth for agent systems. That is strong enough to matter, and narrow enough to be credible. # Staged Adoption Path The pragmatism intent of this work is right, but the adoption path needs to be concrete. A staged deployment model avoids the "all or nothing" objection and shows how existing infrastructure can participate without a full replacement. | Stage | Required Components | What a Deployment Gets | |---|---|---| | **Stage 1: Mission-Lite (AS-only, no management plane)** | Simple Mission record at the AS (`mission_id`, `state`, `exp`, `delegation.max_depth`); one additional validation step at token exchange; a projected Mission reference as an optional claim in issued access tokens; deployment-specific binding of requests to one Mission at a time | Mission authority that can be revoked independently of token expiry; a correlation key across all tokens produced by a Mission; bounded delegation enforcement at the AS | | **Stage 2: Mission Management Plane** | `POST /mission-proposals` and approval endpoints; Mission templates; display representation for approval UX; AuthZEN integration for proposal-time policy evaluation; enterprise approval system integration | Governed proposal and approval flow with attenuation; human-readable consent display; policy-controlled Mission issuance without per-client custom code; reusable templates for common Mission types | | **Stage 3: Cross-Domain and Continuous Evaluation** | Cross-domain Mission assertions; SSF/CAEP event stream; business event integration for condition-based termination; Mission introspection for live state queries; progressive Mission expansion for open-world agents | Mission governance across organizational boundaries; termination triggered by business events, not just clocks; resource servers that can make Mission-aware access decisions without full AS integration | An existing Okta, Auth0, or Azure AD deployment can approximate Stage 1 today with custom authorization server policy, one-Mission-per-runtime-token discipline, and a lookup table or token-bound Mission reference. That approximation does not deliver the full protocol described earlier in this RFC: it is a deployment pattern that captures the core AS-side lifecycle and exchange checks before standardized proposal APIs, PAR-based Mission authorization requests, or Mission introspection are introduced. Stage 1 should be understood for what it is: primarily AS-side Mission governance at issuance and exchange time, not full downstream Mission-aware object-level authorization at every resource server. This is the entry point the architecture should lead with for any team evaluating adoption. Each stage delivers independent value. A team that deploys only Stage 1 gets the core lifecycle and revocation property. Each subsequent stage adds governance depth. This is the pragmatic path that meets the ecosystem where it is today. # Open Questions Rather than an undifferentiated list, the open questions now fall into a few decision clusters. The priority order here reflects what seems most likely to determine whether this architecture becomes practical and spec-worthy. ## Priority 1: Core Viability These questions decide whether the core Mission-Bound OAuth idea is coherent enough to standardize at all. - what is the minimum standard Mission schema, and what remains deployment-specific - should Mission authority be defined as a strict constraint layered on top of scope authority - what is the right projected Mission reference model through RFC 8693 token exchange, especially when the subject token is already bound to one Mission - what normative error model is needed for Mission lifecycle failures at token exchange - whether the first serious profile should require sender-constraining rather than treat it as a strong baseline expectation - what normative requirements the core spec should place on verified agent binding: specifically, whether exchange-time client identity checks, DPoP key continuity across delegation hops, and AS-authoritative actor chain derivation should be MUST-level requirements in the core spec or left to a security profile - how Mission-Bound OAuth should relate to downstream capability attenuation and chaining mechanisms, such as Biscuit-style restriction-bearing tokens, without taking on that whole problem in the core Mission model - whether `mission_ref` and `delegation_chain` should be formally proposed for registration in the IANA JSON Web Token Claims registry (RFC 7519 Section 10.1), and whether a standalone Internet-Draft is needed for the `delegation_chain` claim given its proposed deviation from RFC 8693 `act` nesting semantics ## Priority 2: Open-World Practicality These questions decide whether the architecture actually helps with adaptive agents rather than rebranding closed-world allowlists. - how Missions should express constraint-driven authority beyond explicit allowlists - whether a compiled graph or DAG form should exist between mission authoring and runtime enforcement - how relationship-, process-, and jurisdiction-based constraints should be represented - how bounded authority envelopes should be defined and tuned in practice - whether MCP-derived tool metadata should have a standard mapping into Mission proposals ## Priority 3: Governance and IAM Model These questions decide whether the architecture works as a governance system rather than only a protocol sketch. - how mission authoring, template authoring, and policy authoring should be separated - whether Mission approval belongs inside the OAuth protocol family or in an adjacent management profile - how headless and service-to-service Missions should be provisioned and activated - whether the authorized caller model for `POST /mission-proposals` is the right trust boundary - what is the right normative behavior when CAEP or session-level revocation intersects active Missions - whether Mission amendment (narrowing scope, reducing delegation depth, shortening expiry on an active Mission) should be a first-class operation via a dedicated endpoint, or whether revocation and re-issuance is the only supported path for structural changes - how approval evidence should be represented if approval is delegated to an external workflow or ticketing system ## Priority 4: Enforcement and Resource Server Semantics These questions decide how much of the model resource servers and gateways need to understand. - what parts of Mission state should be exposed to resource servers - how the Mission introspection profile should surface lifecycle and compiled authority - whether the projected Mission reference should be single-handle, pairwise per-audience, or omitted from audience-specific access tokens - what the baseline RS behavior should be when token scope is broader than the Mission's compiled authority region - whether full Mission Authority Model retrieval should remain purely a high-assurance profile or eventually become a more general interoperability mechanism - how deployments should prevent silent downgrade from Mission-aware enforcement to token-only enforcement during outages ## Priority 5: Cross-Domain and Standardization Boundary These questions matter, but they should not block the more local single-domain story. - how cross-domain Mission assertions should be structured and what claim set should cross a trust boundary - whether cross-domain assertions should preserve source Mission references or map to local identifiers - whether the staged adoption model changes what belongs in the core spec versus deployment profiles - which parts belong in a core OAuth draft versus companion specs - how Mission-Bound OAuth relates to GNAP and whether extending OAuth is still the right strategic choice ## Lower-Level Naming and Registration Questions These matter for a draft, but they should be downstream of the architectural decisions above. - how discovery metadata should be named and registered - whether the `authorization_details` type identifier should be `"mission"` - whether the projected Mission reference should be a registered JWT claim and whether it should be string or structured - whether mission templates should be standardized or remain deployment-local - how much prompt-processing behavior should be specified versus treated as implementation guidance # FAQ ## Is this just RAR with more state? No. RAR structures authorization input for a token request. Mission-Bound OAuth adds a durable, lifecycle-governed authority object that survives across token issuance, exchange, suspension, revocation, and business-event termination. ## Why isn't a refresh token enough? A refresh token extends credential continuity. It does not represent a governed authority object with purpose, lifecycle, terminal conditions, approval evidence, and bounded delegation semantics. Mission-Bound OAuth is trying to govern delegated authority, not just prolong token issuance. ## Why not just use GNAP? GNAP is the cleaner architecture for new systems. The practical bet here is that many enterprises will try to solve this inside existing OAuth infrastructure first. Mission-Bound OAuth exists to test whether that incremental path is viable. ## Why isn't AuthZEN or FGA enough by itself? AuthZEN and FGA answer runtime authorization questions. They do not by themselves define the durable authority object that says why this execution exists, how long it should continue, when it must terminate, or what bounded envelope it may explore. The Mission is the missing middle layer between open-ended agent intent and runtime policy decisions. ## What about Biscuit-style attenuation and chained restrictions? That is a real adjacent gap, but it is not the same layer. Mission-Bound OAuth governs whether a delegated Mission should exist, continue, expand, suspend, or terminate. Biscuit-style capability tokens are more about downstream cryptographic attenuation, offline verification, and chained restriction accumulation after authority has already been granted. The important relationship is that any downstream attenuation or chaining mechanism should remain bounded by the Mission and its authority model. Mission-Bound OAuth does not need to solve that whole problem in the first core spec, but it should leave room for separate profiles or companion work that bind attenuation-capable artifacts to `mission_ref`. ## Isn't this too much responsibility for the Authorization Server? Possibly. That is a real operational risk. The architecture is practical only if there is a staged adoption path, selective externalization of policy, and a resilience model that avoids synchronous dependency on the AS for every request. ## Does every deployment need Mission proposals and approval APIs? No. The architecture includes them because they matter for the end-to-end story, but the staged adoption path explicitly allows simpler deployments to start with AS-side Mission records, provisioning-time Mission types, or admin-configured Mission activation before adopting a full management plane. ## Aren't you just inventing another policy language? No. The architecture assumes policy languages and PDPs already exist. The Mission is the governed authority object and compiled context that makes those policy systems usable for delegated agent execution. ## Is the Mission Authority Model a new universal policy language? No. The current design is to standardize the slots, checkpoints, and protocol boundaries, not a universal selector or policy syntax. Different deployments may use different underlying policy engines and compilation strategies. ## Does this require every resource server to become Mission-aware? No. A baseline deployment can keep Mission enforcement mostly at the AS and token-exchange layer. Mission-aware gateways and RSes add stronger runtime guarantees, but they are not the only deployment model. ## Why keep both `mission_id` and `mission_ref`? Because they serve different trust boundaries. `mission_id` is the AS-internal authoritative identifier. `mission_ref` is the projected protocol-facing handle used in tokens, token exchange, introspection, audit, and cross-domain assertions. Separating them improves privacy, tenant isolation, and future cross-domain flexibility. ## Why is `delegation_chain` needed if OAuth already has `act`? `act` identifies the current acting party. It does not give a full ordered multi-hop history in a form that is easy to audit or evaluate across longer agent chains. `delegation_chain` is proposed because Mission-bound delegation is one of the main use cases here, but whether it belongs in the first core spec is still a legitimate question. ## Why not let the AS infer the Mission from the requested resource? Because implicit Mission selection is a confused-deputy risk. The safer model is that the subject token is already bound to one Mission, and the AS uses that binding or verifies an explicitly echoed `mission_ref`. Resource-based guessing would create ambiguity and make cross-mission mixups easier to miss. ## Does this require progressive Mission expansion? No. Expansion is now treated as an optional later capability. A simpler deployment can adopt the stricter rule: if additional authority is needed, create a new Mission. ## Does this solve open-world agent authorization? Not completely. The realistic claim is narrower: it provides a bounded authority object and a governance model that makes open-world agent execution more controllable than token-only OAuth. ## Is `mission_ref` itself sensitive? Yes, at least as operational metadata. It is not an authority credential by itself, but it is still a durable correlation handle. That is why the document treats projection, pairwise handles, tenant-scoping, and controlled exposure as security and privacy concerns rather than implementation details. ## What happens when Mission-aware enforcement is unavailable? The architecture prefers fail-closed behavior for Mission introspection and authority-model retrieval. It should not silently degrade into weaker token-only enforcement unless a deployment explicitly chooses that risk as policy. ## Is cross-domain federation realistic in the near term? Only in limited settings. Same-trust-domain and single-enterprise deployments are the realistic starting point. Cross-domain Mission assertions are likely a later profile, not the first thing the ecosystem will adopt. ## Is this trying to turn OAuth into a workflow engine? No. The goal is narrower: add a governed Mission object that can bind delegated authority to purpose, lifecycle, delegation bounds, and termination semantics. The workflow or agent runtime still lives elsewhere. # IANA Considerations This section documents the IANA registration candidates proposed by Mission-Bound OAuth. All entries are provisional and subject to change based on community feedback. ## OAuth Extensions Error Registry (RFC 6749 Section 11.4) The following error codes are candidates for registration in the OAuth Extensions Error Registry: | Error Code | Usage Location | Description | |---|---|---| | `mission_suspended` | Token endpoint error response | The referenced Mission is in `suspended` state. | | `mission_revoked` | Token endpoint error response | The referenced Mission has been permanently terminated. | | `mission_expired` | Token endpoint error response | The referenced Mission lifetime has elapsed. | | `mission_completed` | Token endpoint error response | The referenced Mission reached its normal terminal state. | | `mission_delegation_depth_exceeded` | Token endpoint error response | The requested delegation would exceed the Mission's `max_depth`. | | `mission_authority_exceeded` | Token endpoint error response | The requested resource or action is outside the Mission's compiled authority region. | | `mission_not_found` | Token endpoint error response | No Mission matching the provided `mission_ref` exists for this client. | | `mission_ref_required` | Token endpoint error response | Multiple active Missions exist for this client and the request did not specify which Mission governs the exchange. | | `mission_expansion_conflict` | Expansion endpoint error response (HTTP 409) | An expansion proposal was evaluated against a prior Mission version; a concurrent expansion was already accepted. Client must re-fetch and resubmit. | | `mission_expansion_outside_envelope` | Expansion endpoint error response (HTTP 422) | The requested extension exceeds the parent Mission's approved authority envelope. A new Mission proposal is required. | ## JSON Web Token Claims Registry (RFC 7519 Section 10.1) **Claim name**: `mission_ref` **Claim description**: Projected Mission reference handle. Identifies the Mission governing the token's authority derivation. Opaque string; value is audience-specific in privacy-sensitive deployments. **Change controller**: IETF **Specification document**: draft-mcguinness-oauth-mission-bound-authorization **Claim name**: `delegation_chain` **Claim description**: Ordered array of actor identity objects representing the full delegation chain. Index 0 is the current immediate delegate (matching `act.sub`); the last index is the originating delegating actor (the first principal to receive delegated authority for the subject). The array grows at the tail as delegation chains extend. Each element contains at minimum `sub` and optionally `sub_profile` and `iss`. **Change controller**: IETF **Specification document**: draft-mcguinness-oauth-mission-bound-authorization ## Authorization Details Types Registry (RFC 9396 Section 10) **Type**: `mission` **Description**: References an approved Mission governing the delegated authority for this authorization or token exchange request. **Required fields**: `type` (string, value `"mission"`), `mission_ref` (string, opaque projected Mission reference) **Optional fields**: none in the core type; deployment profiles may define extensions **Change controller**: IETF **Specification document**: draft-mcguinness-oauth-mission-bound-authorization ## OAuth Parameters Registry (RFC 6749 Section 11.2) No new standalone OAuth token endpoint parameters are proposed. Mission reference is carried via `authorization_details`. ## OAuth Dynamic Client Registration Metadata Registry (RFC 7591 Section 3.2) | Metadata Field | Type | Description | |---|---|---| | `mission_types` | array of strings (URI) | Purpose class URIs the client is permitted to propose | | `mission_delegation_max_depth` | integer | Maximum delegation depth; defaults to 0 | | `mission_approval_mode` | string | `"interactive"`, `"policy_auto"`, or `"pre_provisioned"` | | `mission_resource_categories` | array of strings | Coarse-grained resource type filter applied before template constraints | ## Authorization Server Metadata Registry (RFC 8414) | Metadata Field | Type | Description | |---|---|---| | `mission_proposal_endpoint` | URL | Endpoint for submitting Mission proposals (`POST /mission-proposals`) | | `mission_activate_endpoint` | URL | Endpoint for activating pre-provisioned mission types (`POST /missions/activate`); present only when `pre_provisioned` is in `mission_approval_modes_supported` | | `mission_supported` | boolean | Whether the AS supports Mission-Bound OAuth | | `mission_approval_modes_supported` | array of strings | Approval modes supported by this AS: `"interactive"`, `"policy_auto"`, `"pre_provisioned"` | | `mission_purpose_classes_supported` | array of URI strings | Purpose class URIs the AS accepts in Mission proposals; clients SHOULD check this list before submitting a proposal to avoid 403 failures | | `mission_scopes_supported` | array of strings | Mission management scopes the AS supports; expected values include `mission:propose`, `mission:activate`, `mission:expand`, `mission:authority-model:read`, `mission:introspect:authority` | Mission introspection reuses the existing RFC 7662 introspection endpoint (discovered via the standard `introspection_endpoint` AS metadata field) with `token_type_hint=mission_ref`. No new introspection endpoint URI is needed. # Appendix: Expected Draft Structure If this architecture survives feedback, I expect it to split into something like: - a core Mission-Bound OAuth draft covering Stages 1 and the token model - a mission management and proposal profile covering Stage 2 - a cross-domain mission assertion profile - operational guidance for gateways, eventing, business event integration, and policy integration That is one of the main reasons to publish this as a blog RFC first: to get feedback on where the boundaries should actually be, which parts of the staged model belong in which document, and whether the core claim is actually strong enough to justify standardization. The goal of this work is not to turn OAuth into a workflow engine. The goal is to give OAuth a first-class way to bind delegated machine authority to an approved Mission with purpose, constraints, delegation bounds, and lifecycle. The key claim is narrow and testable: a durable, AS-maintained Mission object that governs token derivation produces meaningfully stronger Mission governance than RAR at individual token issuance points, because it makes Mission authority independently revocable, auditable at the Mission level rather than the token level, and terminable by business events rather than only by clocks. If that claim holds up under feedback, the next step is to extract the pieces that deserve standardization and draft them separately with narrower scope, starting with the Stage 1 core. If you work in OAuth, IAM, policy systems, agent platforms, or enterprise security architecture, the most useful feedback is on the [Priority 1](#priority-1-core-viability) and [Priority 2](#priority-2-open-world-practicality) questions above: whether the core [Mission](#key-terms) object is the right primitive, and whether the bounded authority envelope model is practical enough for real open-world agent systems. --- # Agents Don't Need Your Passport. They Need Your Authority. Canonical URL: https://notes.karlmcguinness.com/notes/agents-dont-need-your-passport-they-need-your-authority/ Markdown URL: https://notes.karlmcguinness.com/notes/agents-dont-need-your-passport-they-need-your-authority.md You've registered your agents as principals in your Identity Provider. You've federated workload credentials, deployed Non-Human Identity controls, and tightened scopes. The agent has an identity, its secrets are vaulted, its access is governed. And your CFO's research agent is still running at 2:05 PM, pulling pre-IPO financials, on a mandate that expired when the board approved the presentation at 2:00 PM. Check every control: the token is valid, authorization policy permitted the request, Just-In-Time (JIT) provisioning and permissions granted time-based least privilege access, and [Continuous Access Evaluation Protocol (CAEP)](https://openid.net/specs/openid-caep-specification-1_0.html) is publishing revocation events. Every layer shows green. The breach is structurally invisible, not because the stack failed, but because no layer of it was built to ask whether the mission behind the request should still be running. When an agent acts on your behalf, it does not need your identity. It needs your authority. Those are not the same thing, and enterprise security stacks were built as if they were. Every IAM control in that stack is optimized for a request-scoped question: may this action proceed right now? The question agents expose is different in kind. It is mission-scoped: should this execution still be running at all? No widely adopted IAM pattern owns that question as a first-class concern. The IAM systems governing enterprise access today were designed around a foundational assumption: humans execute actions. A person authenticates, crosses a boundary, acts, and stops. The security boundary and the execution boundary were the same thing because presence and pacing enforced both. Agents remove those constraints. They don't stop when the task ends. Credentials don't expire when purpose does. The result is ghost execution: an agent executing with valid credentials in service of a mandate that has already expired. NIST's National Cybersecurity Center of Excellence has [identified the gap](https://www.nccoe.nist.gov/projects/software-and-ai-agent-identity-and-authorization) as an active research area, noting in a concept paper that "existing enterprise practices were not built with AI agents in mind." The industry is responding. [Market analysis of the emerging agentic identity space](https://softwareanalyst.substack.com/p/emerging-agentic-identity-access) maps investment flowing toward centralized brokering, Zero Standing Privileges, JIT provisioning, and intent-aware authorization. Better passports, more precisely stamped. That direction correctly addresses the problem the access layer owns. What agents expose is not a flaw in its design. It is what happens when the human who was implicitly governing mission scope is removed from the loop. *Should this execution still be running at all?* --- # ๐Ÿ†” Identity vs. Authority Agents force a distinction that has always existed, but was easy to ignore: - **Identity**: establishes who an actor is at a boundary - **Access**: determines whether a specific request may proceed - **Delegation**: governs what an actor may do on behalf of another - **Authority (Power of Attorney)**: governs whether and how an actor may continue to act A passport lets you cross a border. A Power of Attorney (PoA) lets you act after crossing it. Modern systems have more mature coverage of the first two. Delegation is partially addressed but not standardized end-to-end. Authority, **a purpose-scoped, independently revocable right to act on behalf of another principal**, has no widely adopted equivalent in current enterprise security stacks. That is the gap agents are exposing. Throughout this series, these terms carry specific meanings. **Authority** is the conceptual domain. **Mandate** is the concrete artifact that carries and enforces it. **Power of Attorney** is the legal analogy that makes both legible. | Feature | Identity | Access | Delegation | Authority | |---|---|---|---|---| | Core Question | Who are you? | May this request proceed? | What may this actor do on behalf of another? | Should this execution still be running? | | Duration | Bound to the authentication event | Bound to the token or session lifetime | Bound to the proxy grant | Bound to the mission or purpose | | Enforcement | At authentication | At resource decision points | At delegation points | Throughout the execution lifecycle | | Failure Mode | Impersonation | Unauthorized access | Privilege escalation | Scope creep / ghost execution | # ๐Ÿ›‚ Identity Is Not Authority Enterprise identity infrastructure is mature at both ends of the principal spectrum. Human identity is well-served by decades of federation, authentication, and lifecycle controls. Workload identity is likewise mature, with services authenticating to each other using cryptographically verifiable identities that require no human in the loop. When agents arrived, the natural response was to fit them into one of those two boxes. The first approach is impersonation, in which the agent authenticates as, or with a delegated token from, the user it is acting for. If the user has access, the agent acting as the user has access. The second approach is credential vaulting, which involves provisioning the agent as a non-human principal, vaulting and rotating its credentials, and managing its lifecycle through PAM and NHI tooling. Both approaches have real value. Both fail to reach the problem agents actually introduce. Impersonation conflates identity with authority. The agent does not need to be the user. It needs a bounded mandate to act for the user, scoped to a specific purpose, revocable independently of the user's credentials, and traceable as a distinct principal in audit logs. Impersonating the user gives the agent the full blast radius of the user's identity with no representation of the mission that justified the delegation. Audit logs record the action as the user's. The agent as a distinct accountable principal disappears from access reviews and entitlement audits. Credential vaulting addresses a genuine vulnerability. Standing, unrotated credentials are a real risk. But it addresses the wrong layer. What the agent holds is not the problem. The problem is that the credential carries no connection to the purpose that justified issuing it. PAM and NHI controls govern the credential. Nothing governs the mission. Neither model fits because agents combine properties that span both categories in ways neither was built to accommodate. They operate under delegated human authority, but the access layer records consent without the mission context that makes it meaningful. They discover resources dynamically, which makes pre-enumerated permissions either too restrictive to be useful or too broad to be safe. They chain across principals and trust domains, passing authority in ways the original grantor never explicitly authorized. And they must remain governable for the duration of a specific mission, not just at the moment a token was issued. The question is not what kind of principal an agent is. It is what kind of execution model it requires. ## ๐Ÿ‘ค Why Treating Agents as Humans Fails The first instinct is to provision agents as human users. That pattern is widespread across enterprise deployments. [Cloud Security Alliance Non-Human Identity guidance](https://cloudsecurityalliance.org/research/working-groups/non-human-identity-iam) documents service accounts managed with human-oriented controls across enterprise environments. It is also structurally wrong, and the failure mode reveals something important. The human was not merely the subject of identity controls. The human was the governance layer those controls never had to model. A person authenticates, acts within the scope of their current intent, and stops when the task is done. Sessions terminate because humans close their laptops. Behavioral baselines calibrate to human-paced access patterns. Access reviews reflect what a person needs right now. The controls held not because they were particularly sophisticated, but because the human brought presence, pacing, and natural scope-limiting that the controls never had to formally represent. Agents provide none of that. They **do not stop when the mission ends**. There is no closing-the-laptop signal for a completed task. Behavioral baselines calibrated to human access volumes generate constant noise or, worse, learn to ignore agent activity entirely, removing the last behavioral fallback. When an agent spawns sub-agents, access passes implicitly and in full with no concept of attenuation. Human identity systems were never designed for principals that chain. Provisioning an agent as a human transfers the entitlements without the presence, pacing, or accountability those controls were built around. Agents remove that dependency and make the gap visible. A better human control does not close it. An explicit mandate does. ## โš™๏ธ Why Treating Agents as Workloads Fails The workload model extends this instinct. Govern the agent's credential lifecycle through PAM and NHI tooling, assign it a service identity such as a [SPIFFE](https://spiffe.io/) SVID, and enumerate its permissions in advance. It trades one set of assumptions for a different set of failures. Workload identity systems assume you know every system the workload will call before it runs. Agents operate in open worlds. Given a destination rather than a track, an agent discovers tools, APIs, and data points that were unknown when the mission started. That creates a paradox: restrict it to pre-mapped resources and it cannot do the job it was built for. Give it broad credentials to navigate freely and the exposure scales with every action it takes. | | Workload (Train) | Agent (Taxi) | |---|---|---| | **Path** | Pre-defined tracks | Dynamic, real-time navigation | | **Permissions** | Fully enumerated before departure | Just-in-time, context-dependent | | **Identity** | What it is determines what it can do | Establishes the driver, not the trip | | **Discovery** | Pre-enumerated at deployment | Continuous: the source of its value | > You cannot rely on pre-authorization alone to solve an open-world problem. And even when dynamic policy bridges the discovery gap by evaluating each newly discovered resource against context and purpose at request time, the agent still has no mission object. It knows what it is permitted to do. Nothing tells it when to stop. The discovery problem and the lifecycle problem are separate: solving the first does not solve the second. Identity was designed to answer a different question. Authority requires a different primitive. # ๐Ÿ” Access Is Not Authority Modern security stacks have deep access-layer coverage. Identity providers, authorization servers, and resource servers govern whether an actor may cross a boundary and whether a request is permitted at that point. What happens after falls outside their scope, including how long execution runs, under what conditions, and whether it should continue. Three structural gaps explain why tightening these controls does not resolve the problem: - **Access tokens capture access, not purpose.** They determine whether a request is accepted at a boundary. They do not carry why execution was initiated or when it should end. - **Credential lifecycle is not mission lifecycle.** Credential rotation and token refresh reset the credential clock. The mission clock does not reset with it. - **JIT governs credential windows, not mission state.** JIT credentials and JIT privileges reduce standing exposure. The time window estimates how long the mission will run. When the mission ends before the window closes, or runs longer than expected, the mismatch is invisible to the access layer. Every control in these sections asks whether a specific action is permitted right now. The gap agents expose asks something different. Should this execution still be running at all? An Execution Mandate is stateful in a different dimension. It persists mission context across requests, token refreshes, service hops, and delegation chains. No combination of access-layer controls can answer a question that requires mission state, not because the question is unanswerable, but because answering it requires a component that holds mission state as a first-class artifact. No standard access-layer control is that component. ## ๐Ÿช™ Access Tokens Capture Access, Not Purpose An OAuth access token represents an authorization grant. It encodes what the client is permitted to do, on whose behalf, and for how long. Resource servers evaluate those claims (scopes, audience, subject, expiry) to decide whether a specific request may proceed. What access tokens do not carry is mission context. They record nothing about why the authorization was granted, what conditions must remain true throughout execution, or when it should end. OAuth Rich Authorization Requests (RAR, [RFC 9396](https://datatracker.ietf.org/doc/html/rfc9396)) allow clients to send structured authorization details at request time, specifying not just `scope=finance:read` but a specific purpose (`quarterly_financial_analysis`), resource (`finance/q3-2025`), and authorizing principal (`cfo@example.com`). The authorization server can issue a token scoped precisely to that task. That is the intent-aware authorization the industry has been building toward, and it is meaningful progress. But RAR's declaration is made once, at the moment of the request. It is not a living record of mission conditions across execution. When a user authorizes an agent, OAuth records the grant: the agent's client identity, the user's identity, and the approved scopes. It captures that consent was given. It does not capture why. Consider a code agent authorized to access a production database to investigate a reported incident. The grant records `db:read` on the engineer's behalf. The incident is resolved and the ticket is closed. The grant still shows approval. Nothing in the authorization server knows the ticket was closed. The agent's next request looks identical to its first: a valid client, an approved scope, a consenting user. The context that made the consent meaningful has no formal representation in the grant record. Authorization servers can revoke tokens and invalidate grants, but revocation requires something to trigger it. A board meeting conclusion is not a system event. Short-lived credentials reduce reliance on explicit access revocation, and that is genuine value. Mission revocation is a different problem. It still requires an authoritative lifecycle owner that knows the mission ended and propagation semantics that reach every enforcement point. A shorter token window does not change what triggers it to close. RAR, short-lived tokens, and CAEP can be composed to improve the picture, with intent declared at issuance, tokens expiring quickly, and risk signals triggering re-evaluation. That composition is often proposed as the solution. It is not. Composing components that each answer "is this request currently permitted?" does not produce a component that can answer "should this execution still be running?" RAR captures declared purpose at issuance but does not persist it. Short-lived tokens constrain the entry window but do not track why entry was granted. CAEP propagates signals when events fire but has no standard authoritative source of mission state to emit from. **Tokens enable request-scoped access decisions. Authority governs whether mission-scoped execution should continue.** ## ๐Ÿ—๏ธ Credential Lifecycle Is Not Mission Lifecycle PAM and NHI tooling is essential. It enforces Zero Standing Privileges, vaults secrets, governs non-human credential issuance, and rotates credentials on schedule. These controls manage the credential lifecycle. They govern when credentials exist, how long they last, and how they are refreshed. But the credential lifecycle is not the mission lifecycle. A scheduled rotation fires at 3 AM. The agent now holds fresh credentials for a mission that was cancelled at 2 PM. The credential clock resets. The mission clock does not. PAM governs the credential precisely. Whether the purpose that justified provisioning it still holds is a different question entirely, and no part of the credential lifecycle owns it. ## โฑ๏ธ JIT and Approval Flows Govern Access, Not Mission State When practitioners encounter the mandate continuity problem, the instinct is often to reach for Just-In-Time provisioning or Human-in-the-Loop approval flows. Both reduce credential exposure. Neither tracks whether the mission behind those credentials is still active. Approval flows assume a human-paced world. Agents operate at machine speed. A single agent can invoke dozens of tools per minute, each potentially warranting review under a strict gate model. The volume creates fatigue: reviewers either rubber-stamp requests or respond by broadening grants and reducing gate frequency, which reintroduces the standing access problem JIT was meant to solve. Even when approval flows work as intended, they address individual actions, not mission lifecycle. A human authorizing each tool call is not the same as a human governing whether the mission behind those calls should still be running. JIT credentials and JIT privileges are distinct mechanisms that address different risks. JIT credentials, the PAM and vault pattern, control when a token or secret is issued, ensuring no standing credential exists when the agent is not active. JIT privileges, access activation patterns like Microsoft Entra ID Privileged Identity Management, control which permissions are elevated and for how long, ensuring elevated access is not permanently assigned. Both reduce standing risk. Neither governs whether delegated mission authority should continue after the context that justified it has changed. Both are bounded by a time window estimated to match mission duration. That estimate is a proxy, not a measure. When a mission ends early, the window stays open. When it runs long, credentials refresh without re-authorizing the mission. > A time window is a proxy for mission duration, not a measure of it. Behavior-bounded access models go further. Rather than a fixed window, trust becomes a consumable resource that depletes per action, with continuous intent scoring re-evaluating alignment before each request. That is a meaningful improvement over a timer. It is still not a mission clock. A trust budget depletes when actions are taken, not when the purpose that justified those actions has ended. A cancelled procurement program does not register as budget exhaustion. Behavioral monitoring can flag when an agent's actions diverge from its declared objective. It cannot flag when that objective is no longer valid. # ๐Ÿ”— Delegation Is Not Authority Getting identity right resolves who the agent is. Getting access right resolves what it may do at any given boundary. Neither addresses the handoff. The moment an agent delegates to another agent or spawns a sub-agent, the context established at the original grant does not travel with the authority. That loss of context at the handoff is the delegation problem. The mandate addresses this failure across two distinct dimensions. Mission authority asks whether the purpose and conditions that justified the original grant still hold. Delegation authority asks whether the chain from the current agent to the originating human grant is intact and unattenuated. They fail independently. A structurally valid chain can carry a mission that has already lapsed, and a valid mission can be served by a chain whose originating principal has changed. The three gaps below are delegation authority failures. Standard OAuth delegation defines the first-hop mechanism: a principal authorizes an agent, an authorization server records consent, and a scoped token governs what the agent may do on the principal's behalf. That establishes *what* is permitted, not *why* the grant was made or *when* authority should end. The problem compounds the moment that agent delegates further. Orchestrators spawn sub-agents that invoke tools and call APIs, which delegate to other agents in turn. Authority flows through chains the original principal never explicitly contemplated. In any well-governed delegation model, sub-delegation requires explicit authorization in the original grant: a delegate cannot further delegate absent that, and a grant of authority does not automatically carry the right to extend it. Three structural gaps explain why current systems cannot govern these chains: - **Scope amplifies without attenuation.** Authority passes implicitly at each hop. Even where hierarchical token chains and depth limits constrain chain length, they govern privilege inheritance, not mission scope at each hop. A sub-agent may access more than the mission that justified the original grant. - **Authority chains lack standardized traceability.** There is no standardized way to verify that authority in a chain traces back to an explicit human grant. If the trace breaks, no system can see it. - **Context is not re-evaluated at each hop.** Each delegation point passes authority based on the conditions at the original grant, not current context. The purpose may no longer justify extending it. ## ๐Ÿ”Š Scope Amplifies Without Attenuation When a sub-agent is spawned without mandate context, it operates under its own service role and defaults. It has no knowledge of why it was invoked, what purpose the originating mandate was serving, or what conditions must remain true. It cannot enforce what it cannot see. Hierarchical delegation-token chains with depth limits exist in some frameworks. Even with those controls, the model delegates privileges, not mission intent or execution legitimacy. Cross-system enforcement is difficult because attenuation semantics are not standardized across orchestrators, tools, and trust domains. Token Exchange ([RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693)) is the closest existing mechanism for propagating delegated authority across service boundaries. A client presents a token to an authorization server and receives a new one, scoped for a downstream service, with an `act` claim recording who is acting on whose behalf. The `act` claim is an advisory record of the delegation chain, not an enforced constraint on what that chain may do or how long it may run. Each exchange is a bilateral transaction between one client and one authorization server. Token Exchange moves authority across a boundary. It does not govern whether that authority should still exist. A sub-agent can only receive authority equal to or less than what the delegating agent holds. You cannot delegate what you do not have. With that constraint enforced, the sub-agent cannot reach resources outside the parent mandate's scope. **Without enforced attenuation, every delegation hop is a potential amplification point.** ## ๐Ÿ” Authority Chains Don't Trace Back Without standardized traceability requirements, each additional hop adds a link that no audit log can reconstruct. From the final service's perspective, a request arrived from an authenticated agent with valid credentials. The delegation has no memory of where it started. The problem has a direct analogy in software supply chain security. [SLSA (Supply Chain Levels for Software Artifacts)](https://slsa.dev/) defines provenance requirements so a build artifact can be traced back through its pipeline to a trusted source, with each step attesting to what it received and what it produced. An authority chain has exactly the same requirement. A mandate trace from the current agent to the originating human grant is the identity equivalent of SLSA provenance: every delegation hop attests to the authority it received and what it passed forward. Valid credentials tell you the current agent is authenticated. They do not tell you whether any human authorized the chain of execution that produced it. Authority in any chain must trace back to an explicit human grant. If the trace breaks, the delegation is invalid. [South et al.](https://arxiv.org/abs/2501.09674) (2025) address this requirement directly, proposing cryptographic attestation at each delegation hop to make the chain from sub-agent to originating human grant verifiable without trusting intermediate links to have enforced it. **A delegation chain with no traceable human grant is not governance. It is inherited trust.** ## ๐Ÿ”„ Context Doesn't Travel With Authority At every delegation point, authority passes based on the conditions that existed at the original grant. The question each hop should ask is not only *what authority do I hold?* It is *does the original purpose still justify extending this authority, to this actor, right now?* Short-lived credentials and scoped permissions do not encode any of this. Each delegation decision should reflect current conditions, not those that existed when the original mandate was issued. Without context re-evaluation, revocation does not cascade. When Agent A's mandate expires or is revoked, Agent B's authority continues. The chain outlives its origin. With context re-evaluation enforced, Agent B's authority terminates when Agent A's mandate expires. Short-lived credentials limit how long a window stays open. Context re-evaluation ensures authority cannot outlive the purpose that justified it. Consider the failure in full. A procurement officer delegates a vendor sourcing task to Agent A. Agent A calls a third-party vendor-analysis service, which delegates to Procurement Agent B to retrieve supplier risk scores. The CFO then puts the sourcing program on hold. Agent A's mandate should expire. Agent B has no visibility into Agent A's mandate or the condition that ended it. The vendor-analysis service has no knowledge the program was paused. Agent B continues pulling supplier risk scores, authorized at every access layer, acting on a mandate whose originating purpose no longer holds. Each hop amplified scope. Each hop lost a piece of the trace. Each hop passed authority based on conditions that no longer existed. **Delegation without attenuation, traceability, and context re-evaluation is not governance. It is accidental trust propagation.** --- The gap is not in your controls. The gap is in what your controls were built to govern. Identity, access, and delegation each answer their question correctly, and none of their questions is the one agents expose. Closing it requires a control that holds four properties as a persistent, independently revocable artifact. The purpose for which authority was granted. The conditions under which it remains valid. The lifecycle events that end it. And the provenance tracing it back to a human decision. Identity establishes who, not why. Access governs the request, not the mission. Delegation carries authority forward but holds no record of the mission that justified it or the conditions under which it should terminate. None of the three owns all four properties. The missing layer must exist as a distinct first-class artifact, not as an extension of any existing one. We have been building better passports. What agents need is Power of Attorney. That is the artifact the next post defines. --- # From Passports to Power of Attorney Canonical URL: https://notes.karlmcguinness.com/notes/from-passports-to-power-of-attorney/ Markdown URL: https://notes.karlmcguinness.com/notes/from-passports-to-power-of-attorney.md Governing the stay requires an artifact that no current control provides. For delegated authority to remain trustworthy throughout execution, it must carry four things. The purpose for which it was granted. The conditions that must remain true while it runs. The lifecycle events that end it. And the provenance that traces it back to a human decision. Identity controls establish who the agent is, not why. Tokens govern what is permitted, not the conditions under which permission holds or the business milestones that close it. Policy engines evaluate each request against current policy but in standard deployments maintain no record of the mission that originated the request, or whether that mission remains valid. Together they answer every question except the one that matters. Should this execution still be running? No widely adopted primitive holds purpose, conditions, lifecycle, and provenance as a first-class artifact. That is what the Execution Mandate is. # โš ๏ธ The Enforcement Gap What is missing from the current stack is not an enforcement mechanism. Policy engines can evaluate mandate conditions once the state is present. What is missing is a state owner. No widely adopted control-plane component holds mission authority as a first-class, independently revocable artifact, and without that, every enforcement point in the stack is answering the wrong question. In enterprise operations, a badge proves you can pass checkpoints. A work order defines what job is authorized, under what constraints, and when that job is complete. **[Zero Trust](https://csrc.nist.gov/publications/detail/sp/800/207/final) is the badge. Power of Attorney is the work order.** The badge can stay valid after the work order is closed. Zero Trust requires that every request be re-evaluated against current identity and policy. That verification is request-scoped. It checks the request, not the mission. The failure takes four forms: | Failure Mode | Category | |---|---| | Mission ends but access persists | Mission authority failure | | A conflict emerges that did not exist at issuance | Mission authority failure | | Authority transfers to a principal who no longer holds it | Delegation authority failure | | Delegation amplifies scope beyond the original grant | Delegation authority failure | The two cases below are one of each kind, and the subtlest, because in each the mission itself is still running. - **The "Conflicted Reviewer" (Mission Authority Failure):** An expense audit agent is authorized by an analyst to review the team's travel submissions. During execution, the analyst is added as a required approver for one of the expense reports in scope, creating a separation-of-duty conflict that did not exist at issuance. The agent is now auditing a record its principal must approve. The mission is still active. A reviewer assignment is not an IAM event. Nothing in the stack can see it. - **The "Delegated Approver" (Delegation Authority Failure):** A legal due diligence agent is authorized by General Counsel to review acquisition target contracts. Midway through the review, GC recuses herself due to a personal conflict of interest and formally delegates her authority to outside counsel. The agent's mandate traces back to a principal who no longer holds authority over that decision. The mission is still active. The token is still valid. A recusal is not an IAM event. Nothing in the stack can see it. Authorization is a decision mechanism. Whether role-based, attribute-based, policy-based, or relationship-based, access control models evaluate whether a specific request is permitted under current policy. They can encode context and purpose attributes, but each decision is local to a single request. The question they cannot ask is **"Should this actor still be acting at all?"** Consider a CFO who authorizes a research agent to access pre-IPO financial data to analyze board exposure and prepare a presentation. The board approves the draft at 2:00 PM. The mission is complete. Check every control five minutes later: - Access Token: valid โœ“ - Fine-grained authorization (FGA): agent has financial read access โœ“ - Just-In-Time (JIT): credential was legitimately provisioned โœ“ - [Shared Signals Framework (SSF)](https://openid.net/specs/openid-sharedsignals-framework-1_0.html)/[Continuous Access Evaluation Protocol (CAEP)](https://openid.net/specs/openid-caep-specification-1_0.html): no identity risk event to propagate โœ“ - Security Information and Event Management (SIEM): no anomalous behavior โœ“ - **Mandate: expired at 2:01 PM โœ—.** Nothing in the stack can see it. No alert fires. No log entry looks wrong. The breach is structurally invisible. The response to this scenario is often to point to delegation-token chains with depth limits and reduced scope. If the chain is shallow and the token is narrow, surely the blast radius is contained. Even with those controls, the problem persists. A depth limit governs how far authority propagates. A reduced scope governs which resources the agent may access. Neither provides a canonical place to represent that this mission ended at 2:00 PM and to force every enforcement point to converge on that fact. The chain has no concept of the purpose that justified it. The more sophisticated objection is that existing primitives, composed correctly, could approximate the same result. [Rich Authorization Requests (RFC 9396)](https://datatracker.ietf.org/doc/html/rfc9396) carry structured purpose declarations at token issuance. Short-lived tokens limit credential exposure. CAEP propagates revocation signals. A fine-grained PDP evaluates contextual conditions per request. Each addresses a real problem. The composition still fails on the same point. RAR declares purpose at issuance but has no revocation semantics tied to whether that purpose remains valid. Short-lived tokens refresh independently of mission lifecycle. A 15-minute token does not terminate when the mission does. It gets refreshed. CAEP can propagate a mandate-expiry signal, but without a standardized source of mission state there is nothing to propagate. A PDP evaluates whether each request is permitted, not whether the mission that originated the request is still valid. Composed correctly, these controls close access gaps and reduce blast radius. None of them creates a state owner for mission authority. That is the role that has no current occupant. The breach also leaves a clean audit trail. Every request was authorized. Every control showed green. Post-incident, the access logs contain no evidence of what the agent's mission was, when it was supposed to end, or which actions exceeded it. The failure is invisible not just at the moment it occurs but in the reconstruction. A mandate record changes this. Every action executed under a mandate is attributed to a specific delegated purpose, the grant that authorized it, and the agent instance that executed it. Mandate expiry is a first-class event in the audit log. An investigator can ask whether this action was taken while the mandate was valid or after it expired. That question has no answer in today's access logs. It is the difference between a record of what happened and a record of what was authorized to happen. Those two things diverge the moment a mission ends and the agent keeps running. That distinction matters not just in incident response but in routine governance. A mandate record gives reviewers and auditors what they currently lack. A structured attestation linking every action to a named human grant, a declared purpose, and a defined lifecycle. Compliance reviews can validate not just that access was assigned but that it was used within its authorized scope and terminated when that scope ended. The gap manifests across every dimension of agentic execution: | Failure Mode | Current Stack | With a Mandate Layer | |---|---|---| | Mission Completion | Agent continues acting while token and policy checks pass | Authority expires when the objective is met, independently of token validity | | Tool Discovery | Either block the agent or grant broad credentials | Scoped, one-time authority derived from the active mission | | Sub-Delegation | Agent passes full credentials to sub-agents | Agent passes an attenuated mandate, never more than it holds | | Compromise | Attacker gains the full scope of the agent's credentials | Attacker is constrained to the active mission's scope | # ๐Ÿ“œ Authority Is Power of Attorney We have been issuing passports. The right instrument has always been Power of Attorney. A passport establishes who you are and authorizes you to cross a boundary. A visa goes further, declaring a purpose and duration, but it still governs only the entry. It does not evaluate whether the purpose that justified the entry remains valid. It was the right instrument for a world where the entity crossing the boundary would stop when the task was done. It is the wrong instrument for an agent that will keep running until something tells it to stop. The industry has responded to agent security by building better passports and better visas: tighter scopes, shorter lifetimes, faster rotation, more precise intent declarations at issuance. These are improvements. They are improvements to the wrong instrument. When an agent acts on your behalf, you are not giving it your identity or your credentials. You are granting it **Power of Attorney**. A Power of Attorney (PoA) is a delegated mandate to act on behalf of another. It is bounded by **purpose, scope, time, and conditions**. It can be limited, revoked, and evaluated independently of identity. You might grant medical Power of Attorney, but not financial. You might grant limited financial authority, but not real-estate authority. The authority is scoped to *why* someone may act, not merely *which actions* are technically possible. The Execution Mandate is the artifact that carries and enforces it as a signed, independently revocable record. The same dimensions apply directly to agents. An agent authorized to source a backup logistics vendor holds authority for a specific purpose (vendor sourcing under pre-approved terms), a specific scope (that vendor market and contract templates), a defined time window (the active contingency program), and defined conditions (the program remains active). When any dimension changes, the authority terminates, regardless of whether the agent's token remains valid. One dimension the PoA analogy surfaces that the access model often obscures is that you can only grant authority you actually hold. In enterprise practice, this breaks down more often than the access layer reflects. A manager who authorizes an agent to process HR records may have read access to those records without owning them. The data governance function that does own them has independent policy interests the delegating principal's grant does not represent. Resource owner consent and delegating principal intent are distinct inputs to authorization. Treating them as one is a meaningful gap in the consent model, and for sensitive or regulated data the mandate should reflect both. Mandates originate in human decisions. In the simplest case, the consent moment looks similar to an OAuth authorization flow: the principal reviews the agent's declared purpose, scope, and conditions before approving. The difference is what gets recorded. An OAuth grant records that consent was given. A mandate grant records the purpose, the conditions under which it holds, and the events that will end it. The richer record is what makes the mandate evaluable throughout execution rather than only at issuance. This distinction has roots in capability-based security. Object-capability systems addressed what Norm Hardy described as the [confused deputy problem](https://dl.acm.org/doi/10.1145/54289.871709) in 1988. A confused deputy misuses authority granted for one purpose to serve another. The agent mandate problem is the temporal extension of that failure. The mandate layer closes the temporal dimension. It restricts not just what authority may be exercised at any moment but how long that authority runs and under what conditions it remains valid. The theoretical grounding for continuous authority evaluation comes from Park and Sandhu's [Usage Control (UCON) model](https://dl.acm.org/doi/10.1145/984334.984339) (2004), which distinguished between conditions evaluated at the moment of access and conditions that must remain true *throughout* an ongoing action (what they called continuity obligations). The Execution Mandate operationalizes that distinction. Conditions are not checked once at grant time. They are evaluated per action throughout the mission lifecycle. What UCON established as a theoretical property, agentic systems make a deployment requirement. The theory was right in 2004. The urgency is new. # ๐Ÿ‘ป Case Study 1: Code Agent and Ghost Execution **The Scenario:** A team grants a code agent access to GitHub and Slack to monitor PR status and notify when a merge completes. **The Access Layer Failure:** The PR is merged at 2:00 PM. The mission is over, but the token remains valid until 2:00 AM. The agent continues polling the private repository for 12 hours, still authorized at the access layer but no longer authorized by its mandate. **The PoA Solution:** The agent holds an Execution Mandate with a condition bound to PR state: *"Authority valid only while PR #123 is pending merge."* When status changes to merged, the mandate is invalidated. Even if the token remains valid, subsequent requests are denied. The mission is complete, so execution stops. # ๐Ÿš• Case Study 2: The Taxi and Unchecked Discovery **The Mission:** "Source and onboard a backup logistics vendor under pre-approved terms, then prepare the purchase order package for review." **The Workload Failure:** If the agent discovers a supplier portal or risk-screening API that was not in its original pre-approved list, the request is blocked. The agent fails because it cannot leave the tracks. **The Access Layer Failure:** To prevent this type of failure, teams grant agents broad procurement roles or admin credentials. If the agent touches a malicious integration or compromised endpoint, it has the tokens and permissions to take actions far beyond the original sourcing task. **The PoA Solution:** The agent is governed by its mandate. When it discovers a new supplier portal or sanctions-screening API, the authority layer asks: *"Does calling this further the `backup_vendor_sourcing` mission and stay within approved terms?"* If yes, a one-time attenuated Execution Mandate is issued specifically for that endpoint, scoped to one resource, one action, for the duration of that call. The sub-agent cannot further delegate, because its mandate is derived from the original mission scope and cannot exceed it. If the procurement program is cancelled, the parent mandate is revoked and the sub-agent's authority terminates with it, regardless of whether any individual credential remains valid. The two failure modes above are not edge cases. They are the only options the pre-authorization model offers. Restrict the agent to pre-enumerated resources and it cannot execute in an open world. Grant broad credentials and every discovery is an expansion of blast radius. The mandate breaks that binary. Discovery is evaluated against mission scope, not against a pre-approved list. Execution governance is not a more sophisticated form of pre-authorization. It is a different control operating at a different layer. # ๐Ÿ“‹ The Execution Mandate in Practice Those two scenarios converge on a common set of requirements. For mandate governance to hold, delegated authority must be: - explicitly represented - bounded by purpose, scope, time, and conditions - inspectable as execution unfolds - governable independently of credentials - terminable when the mandate expires, even if access would still succeed The concrete form of that authority is an **Execution Mandate**: a signed, inspectable record that runtime systems can evaluate and revoke independently of whether the underlying token remains valid. At minimum it should carry: - **principal**: who granted it - **agent**: who holds it - **purpose**: why it exists - **scope**: what it covers - **conditions**: what must remain true - **lifecycle**: when it ends - **delegation**: how authority passes to sub-agents - **delegation chain**: full provenance from the originating human grant to this agent The mandate can be structured in several formats. [Macaroons (NDSS 2014)](https://research.google/pubs/macaroons-cookies-with-contextual-caveats-for-decentralized-authorization-in-the-cloud/) enforce attenuation structurally through HMAC-chained caveats. [Biscuit](https://www.biscuitsec.org/) uses Datalog-based logic to express richer conditions directly in the token. Both are promising primitives for mandate attenuation but have limited enterprise adoption and production track record today. A signed [JSON Web Token (JWT, RFC 7519)](https://datatracker.ietf.org/doc/html/rfc7519) has the broadest enterprise tooling support and deployment experience, making it the practical starting point for a minimum viable mandate implementation, with online/offline attenuation tradeoffs handled at the control plane layer. For the mandate to be enforceable rather than advisory, it must be cryptographically bound to the token it governs, either by embedding a mandate reference in a token claim or by including a token hash in the mandate, so that presenting a valid mandate alongside an unrelated token is detectable at any enforcement point. This authority must remain anchored to the initial grant. An agent operating in an open world will inevitably discover new tools and data, but it must never be allowed to self-authorize into new permissions. The mandate can be amended only by the granting principal or explicitly delegated administrators. The agent executing under it has no amendment rights. Authority over the mandate's lifecycle is held by the granting principal. The mandate continues until a defined terminal event fires, the granting principal revokes it, or its lifecycle expires. The agent governs none of these. > An agent that can rewrite its own mandate has no mandate at all. ## ๐ŸŽซ What the Mandate Carries That a Token Cannot For the procurement agent in Case Study 2, a mandate structured as a signed JWT would look like this: ```json { "jti": "mnd-logistics-sourcing-7f2a", "iss": "https://mandate.example.com", "iat": "2025-10-01T08:00:00Z", "exp": "2025-10-15T17:00:00Z", "sub": "urn:agent:procurement/vendor-sourcing@3.2", "aud": ["https://enforcement.example.com", "https://vendor-portal.example.com"], "principal": { "sub": "vp-supply-chain@example.com", "iss": "https://idp.example.com", "grant_ref": "gnt-oauth-c9d3e1" }, "agent": { "instance": "inst-7f2a-b8c4" }, "purpose": { "objective": "Source and onboard a backup logistics vendor under pre-approved terms", "business_context": "Contingency supplier program, primary vendor SLA breach Q4-2025" }, "authorization_details": [ { "type": "vendor_portal", "locations": ["https://vendor-portal.example.com"], "resource": { "category": "logistics", "region": "north-america" }, "actions": ["search", "view_profile", "initiate_onboarding"], "constraints": { "contract_template": "standard-logistics-v3", "spend_tier": "pre-approved" } } ], "conditions": [ { "id": "program-active", "expression": "procurement.contingency_program.status == 'active'", "evaluation": "per_action", "on_failure": "suspend_and_notify" }, { "id": "sod-clear", "expression": "principal.conflicted_vendors.contains(request.vendor_id) == false", "evaluation": "per_action", "on_failure": "halt_and_escalate" } ], "lifecycle": { "hard_expiry": "2025-10-15T17:00:00Z", "terminal_events": ["vendor_onboarding.completed", "contingency_program.cancelled"], "on_expiry": "revoke_and_cascade" }, "delegation": { "permitted": true, "max_additional_hops": 1, "attenuation": "strict_subset_of_parent", "cascade_revocation": "immediate" }, "delegation_chain": [] } ``` The specific field names are illustrative. The structural requirements are what matter: | Field | What it carries that an access token cannot | |---|---| | `principal` | The human identity that authorized this execution: traceable, auditable, independent of the agent's own identity | | `agent` | The specific agent instance holding this mandate: a distinct principal in audit logs, not the user it acts for | | `purpose` | Evidence traceable to a human grant: objective and business context, not a scope string | | `authorization_details` | Typed resource objects with per-resource actions and constraints, not scope strings | | `conditions` | Checks evaluated per action throughout execution; if the contingency program is cancelled, execution suspends before the next call | | `lifecycle.terminal_events` | Business milestones that end the mission, not only a timer | | `delegation` | Attenuation rules every child mandate must satisfy: strictly less scope, strictly sooner expiry, no further delegation | | `delegation_chain` | The full chain of mandate grants from the original human authorization to this agent, inspectable at any point during execution | The payload serves both dimensions. The purpose, conditions, and lifecycle fields govern mission authority. They ask whether the mandate's conditions and purpose remain valid throughout execution. The principal, delegation, and delegation_chain fields govern delegation authority. They ask whether the chain from this agent to the originating human grant is intact and unattenuated. A mandate can fail on either dimension independently of the other. A mandate record also transforms the audit trail and the governance record. Every action is attributed to a specific delegated purpose, the expiry of that purpose is a first-class event, and post-incident review can distinguish authorized access from authorized access *after mandate expiry*, a distinction invisible in today's access logs. The same record gives access certifications, compliance audits, and regulatory reviews what they currently lack. A structured attestation linking agent activity to a human decision, a declared scope, and a defined end. --- The Execution Mandate is the artifact the existing stack does not yet hold. It is what makes delegated execution governable rather than merely authorized. Building the layer that enforces it is where the next post goes. --- # Governing the Stay, Not Just the Entry Canonical URL: https://notes.karlmcguinness.com/notes/governing-the-stay-not-just-the-entry/ Markdown URL: https://notes.karlmcguinness.com/notes/governing-the-stay-not-just-the-entry.md The previous post defined the Execution Mandate. This post builds the layer that makes it operational. A Power of Attorney document sitting in a filing cabinet grants nothing. The document establishes the authority. The system that issues, enforces, propagates, and terminates it is what makes that authority real. The Execution Mandate is the document. The system that makes it real has four working parts. 1. **Mandate service**: owns mission state as an authoritative, independently revocable artifact evaluable throughout the execution lifecycle 2. **Continuous authority evaluation**: a policy layer that asks whether execution should continue, not just whether a specific request is permitted 3. **Cross-domain mandate propagation**: portable mandate authority that crosses organizational and trust boundaries with verifiable chain of custody 4. **Orchestration-layer enforcement**: authority governance embedded in how workflows manage execution lifecycle, not only at access gates They are not independent improvements. The mandate service creates the state owner. Continuous evaluation consumes it. Cross-domain propagation extends it. Orchestration enforcement lands it. Each primitive addresses a different failure mode. The first two enforce mission authority. They ask whether the mandate's purpose, conditions, and lifecycle remain valid. The third enforces delegation authority across organizational boundaries. The fourth lands both at the execution layer. Together they make it possible to delegate authority to autonomous systems with the same confidence you delegate it to humans, with defined scope, revocation rights, and a clear end. --- # ๐Ÿ“‹ Mandate Service The mandate service is what turns the Execution Mandate from a document into an enforced constraint. What follows covers its architecture and integration, lifecycle and revocation, authority and delegation, and hardening as critical infrastructure. ## ๐Ÿ—๏ธ Architecture and Integration The mandate service is an architectural pattern that can be deployed as a standalone component, a capability added to an existing authorization server, or a module embedded in the orchestration layer. What matters is the function. Authoritative mission state ownership with clear enforcement integration points. The mandate service does not replace existing Identity and Access Management (IAM) infrastructure. It sits above it. The Identity Provider (IdP) establishes identity. The authorization server governs token issuance. Both feed into the mission record the mandate service holds, which can terminate execution independently of whether the token remains valid. Enforcement can sit at the orchestration layer, an authorization sidecar, or a gateway. The integration point is not where authentication happens but where execution continues. Clarity about which component owns which question matters. The IdP answers questions of identity. The authorization server answers whether a token grant is valid. The policy engine answers whether a specific request is permitted under current policy. The orchestrator answers what an agent is doing at any given moment. The mandate service answers whether the mandate behind a request is still valid and whether that execution should continue. Each is authoritative in its domain. None substitutes for the others. Mandate governance is a distinct concern from the two systems it sits between. Workflow state tracks what is happening in execution right now. Policy engines evaluate whether a specific request is permitted under current policy. Mandate governance asks whether the mission behind those requests should continue at all. That question cannot be derived from workflow state or from policy decisions. It requires a separate artifact that holds mission authority as a first-class, independently revocable record. The trust directions within that architecture matter as much as the boundaries. The policy engine reads from the mandate service as a context source. The mandate service does not defer to policy decisions or to the orchestrator's local execution state. Business systems emit terminal events and the mandate service owns the revocation decision. Writes to the mandate service are restricted to the granting principal and explicitly authorized policy administrators. Mission state authority is held by the mandate service alone. The others enforce, inform, or execute. None governs. For teams with existing policy infrastructure, the mandate service does not need to replace the Policy Decision Point (PDP). It can function as a context source, with the Policy Enforcement Point (PEP) querying the mandate service as part of its decision inputs and the PDP evaluating mandate state alongside identity claims and resource policy. This allows mandate governance to integrate with [Open Policy Agent (OPA)](https://www.openpolicyagent.org/), [Cedar](https://docs.cedarpolicy.com/), or [OpenID AuthZen](https://openid.net/wg/authzen/) deployments as a context source rather than requiring a separate enforcement path. The enforcement timing is fixed regardless of architecture. Mandate checks must happen before tool invocation and before any irreversible action. A post-action check is not enforcement. ## ๐Ÿ”’ Lifecycle and Revocation The mandate service is the authoritative system of record for mission state. It owns whether a mandate was issued, under what terms, and whether it remains valid. Business systems are the sources of terminal events. A procurement platform signals a program was cancelled, a CRM records a renewal conversation closed, a ticketing system marks a task complete. Those signals flow to the mandate service, which evaluates them against lifecycle conditions and triggers revocation when they match. Every revocation is a first-class security event, recording who revoked, when, under which terminal condition, which child mandates cascaded, and what in-flight actions were halted. That record is reviewable independently of the underlying access logs and survives the token rotation cycles that would otherwise erase execution history. Three authority questions govern the mandate lifecycle. The mandate is issued by the granting principal through the consent flow. The mandate service owns its ongoing state. Revocation rights belong to the granting principal, delegated administrators, and the terminal events defined in the mandate's lifecycle conditions. Business systems report what happened. The mandate service decides whether it constitutes a terminal condition. ## ๐Ÿค Authority and Delegation Policy authority over mandates is not held by the agent. It belongs to the granting principal, the human who authorized the delegation. Organizations may extend this authority to additional parties, including security teams, compliance officers, and designated administrators, each with defined scope over issuance, amendment, and revocation. When mandates conflict, the more restrictive constraint governs. Conflicts that cannot be resolved by scope intersection require human escalation before execution continues. When an agent needs to delegate to a sub-agent, the mechanics of attenuation are worth making explicit. The delegating agent cannot self-issue a child mandate. It submits a delegation request to the mandate service, declaring the sub-agent's identity, the scope it requires, and the conditions that should apply. The mandate service validates that the requested scope is a strict subset of the parent's scope, that the requested expiry falls within the parent's lifecycle, and that the parent mandate explicitly permits further delegation. The mandate service records the parent-child relationship, which is what makes cascade revocation possible when the parent mandate terminates. This is where the tradeoff between online and offline attenuation surfaces. Offline attenuation (the [Biscuit](https://www.biscuitsec.org/) and [Macaroons](https://research.google/pubs/macaroons-cookies-with-contextual-caveats-for-decentralized-authorization-in-the-cloud/) pattern, where the agent adds caveats directly to its own token without a round-trip) enforces strict-subset semantics structurally and is useful for latency-sensitive cross-domain calls. The cost is auditability. The mandate service has no record of what was delegated, to whom, and under what conditions, which makes cascade revocation across unknown chains unreliable. For deployments where auditability and cascade termination are first-class requirements, online attenuation through the mandate service is the right model. For teams starting with [JWT](https://datatracker.ietf.org/doc/html/rfc7519)-based mandates, conditions live outside the token and attenuation requires a service round-trip rather than in-token caveats. Those constraints are real and worth understanding before choosing a format. Mandate issuance is the point at which Separation of Duties (SoD), dual control, and break-glass requirements must be explicitly modeled. A mandate cannot confer authority the granting principal is themselves prohibited from exercising under SoD policy, and SoD conflicts that emerge during execution should be expressible as conditions evaluated continuously, not only at issuance. High-value mandates may require co-authorization at the consent flow. Break-glass access should be modeled as a separate, time-bounded, heavily audited emergency mandate rather than a silent widening of an existing one, keeping the governance record intact and the deviation visible. ## ๐Ÿ›ก๏ธ Critical Security Infrastructure Like any authoritative control-plane component, the mandate service must be treated as a high-value target. Compromise of the mandate service is compromise of execution governance across every agent it controls. Hardening requirements mirror those of authorization servers. Artifacts must be signed so enforcement points can validate mandates without a live callback. Fail-closed behavior is required so that an unavailable mandate service halts execution rather than defaulting to open. Operational policy must define explicit cache staleness bounds, local verification of signed artifacts to reduce live-callback dependency, and revocation lag tolerance calibrated to the risk profile of the actions governed. Every mandate issuance, amendment, and revocation is a first-class security event with a full audit record. # ๐Ÿ”„ Continuous Authority Evaluation Getting issuance right is necessary. It is not sufficient. The authority layer must ask not *is this request permitted?* but *should this execution still be running?*, evaluated against current context at runtime, not only at the moment a token was issued or a gate was crossed. > A mandate that is checked only at issuance is not a mandate. It is a declaration. Park and Sandhu's [UCON model](https://dl.acm.org/doi/10.1145/984334.984339) made this precise in 2004. Continuity obligations must hold throughout an ongoing action, not only at access time. The insight did not translate to deployment. Request-scoped controls were sufficient when humans were managing execution and closing the continuity gap themselves. Agents remove that assumption. CAEP and Zero Trust provide continuous access evaluation, re-evaluating whether a specific credential or request is still valid as conditions change. Behavior-bounded trust models add a third layer, tracking whether each action aligns with the stated objective and consuming a finite trust budget rather than relying on a static grant. The mandate layer provides continuous mission evaluation. It asks whether the execution behind those requests should still be running at all. Continuous evaluation does not mean a synchronous round-trip to the mandate service on every API call. That model does not scale at production volumes and creates a single point of failure. The operational approach is hybrid. High-value or irreversible actions trigger a synchronous mandate check before execution. High-volume low-risk calls assume the mandate valid until a revocation signal arrives via [Shared Signals Framework (SSF)](https://openid.net/specs/openid-sharedsignals-framework-1_0.html)/[Continuous Access Evaluation Protocol (CAEP)](https://openid.net/specs/openid-caep-specification-1_0.html). The mandate service pushes revocation when a terminal event fires, and ghost execution stops at enforcement points without gating every API call. Which action type applies should be policy-defined by risk and reversibility, not left to ad hoc runtime behavior. The semantic substrate for continuous evaluation is an open problem. The mandate service needs to know what "the contingency program is active" means at runtime, but business vocabulary does not map cleanly to discrete IAM events. Rather than waiting for system events that may never arrive, one promising approach is to maintain a structured, queryable artifact that captures the ongoing state of the world the mandate was issued into (negotiations active, renewal open, procurement program running). The mandate service evaluates conditions against that artifact rather than raw system signals. [Context graphs](https://foundationcapital.com/context-graphs-ais-trillion-dollar-opportunity/) formalize this pattern, making the graph the semantic bridge between business vocabulary and policy-evaluable state. For conditions that cannot be instrumented against machine-observable signals, the mandate shifts from condition-based to event-based expiry. A mandate can terminate when the CFO approves the disbursement, when the renewal conversation closes, or when the partner organization's data-processing agreement lapses. The agent stops precisely when the human task completes or the governing relationship changes, without requiring manual security reviews during execution. The re-authorization trigger is the business event, not the clock. When conditions cannot be instrumented against machine-observable signals, the mandate falls back to hard expiry. That might seem to reduce it to Just-In-Time (JIT) with extra steps. It does not. JIT issues a credential window. A mandate issues a governed mission. Even in the hard-expiry fallback, the mandate carries what JIT cannot. It holds an authoritative mission record the rest of the security stack can query, a cascade revocation chain that fires when the mandate terminates, attenuation semantics that govern every delegation hop, and an audit trail that attributes execution to a specific delegated purpose rather than a credential issuance. As instrumentation improves and event surfaces expand, the condition model grows with it without requiring architectural changes. The hybrid model surfaces tradeoffs that have no universal answer. Revocation signals via SSF/CAEP are not guaranteed delivery, and stricter fail-closed behavior reduces exposure but creates availability risk. The right balance depends on the risk profile of the actions involved, the reversibility of side effects, and the availability cost the organization will accept when the mandate service is unavailable. What the model requires is that these tradeoffs be made explicitly and policy-defined, not left to ad hoc runtime behavior. A mandate layer that does not specify its failure semantics is not a governance layer. # ๐ŸŒ Cross-Domain Mandate Propagation The two primitives above describe what governance looks like within a single deployment. Agent chains do not stay within one. [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers are third-party. [Agent-to-Agent (A2A)](https://google.github.io/A2A/) protocols cross organizations. Tool ecosystems span multiple vendors and trust domains. The mandate design has cross-domain portability built in. A mandate structured as a signed [JSON Web Token (JWT, RFC 7519)](https://datatracker.ietf.org/doc/html/rfc7519) or [Biscuit](https://www.biscuitsec.org/) token can be verified at any enforcement point without a callback to the issuing authority, and attenuation semantics ensure each delegation hop can only narrow scope, never amplify it. A receiving system can validate an incoming mandate at its boundary before accepting delegated authority, without requiring shared infrastructure with the sender. Mandate payloads may carry sensitive business context. In cross-domain scenarios, downstream enforcement points do not always need the full payload to enforce it. A mandate can carry a reference handle in place of the full purpose description, with the authoritative record held by the issuing domain's mandate service. Sensitive fields can be audience-restricted so only designated enforcement points can inspect them. Full cross-domain governance requires infrastructure that current standards do not yet provide. Federated trust hierarchies, distributed revocation via SSF/CAEP across organizational boundaries, and interoperable condition schemas remain open problems. A single organization can issue, enforce, and revoke mandates within its own deployment with no cross-domain infrastructure at all. At the boundary, the portable mandate design described above provides the necessary tools. Signed artifacts enable validation without shared infrastructure. Attenuation semantics prevent scope amplification at each hop. Reference handles keep sensitive context on the correct side of the boundary. [OpenID Federation](https://openid.net/specs/openid-federation-1_0.html) and SSF/CAEP provide the trust and revocation infrastructure the cross-domain case will eventually require. Most deployments can achieve substantial mandate governance before that infrastructure arrives. # โš™๏ธ Orchestration-Layer Enforcement At the orchestration layer, the three primitives above become operational. When a mandate expires, orchestrators must be able to pause, unwind, or terminate execution, not merely block at the next gate. The [saga pattern](https://dl.acm.org/doi/10.1145/38713.38742), which coordinates distributed transactions through compensating actions that undo partial work if a step fails, is a useful analogy here, not a direct implementation model. What the analogy captures is the key operational requirement: not every in-flight action can be undone, and the orchestrator must know the difference before execution begins. If the vendor sourcing mandate expires while the agent is retrieving a supplier profile, halting the retrieval is straightforward. If it expires after an onboarding workflow has already been initiated, unwinding is not possible without human review. The mandate layer makes this distinction explicit at authorization time, defining which actions within the mission scope are reversible. That is what transforms mandate termination from an access control event into a governed unwinding of execution state. Reversibility is declared at mandate issuance, not inferred by the orchestrator at runtime. The mandate defines the unwinding contract before execution begins. In practice this requires explicit handling for revocation lag, in-flight requests, and compensating transactions. The hybrid evaluation model described above (synchronous checks for high-value actions, signal-based revocation for high-volume calls) maps directly onto orchestration-layer enforcement. The orchestrator knows which actions require a mandate check before proceeding and which can proceed under the assumption of a valid mandate until a revocation signal arrives. For agent teams, the operational payoff is concrete. Instead of debating how long a Just-In-Time (JIT) window should be, teams define the terminal events for a mission at authorization time. The security team can audit those definitions. Compliance can validate them against policy. The agent executes until a defined business milestone, not until a timer fires. [Faramesh](https://arxiv.org/abs/2601.17744) (Fatmi, 2026) proposes a complementary research architecture for this enforcement layer. Authority Attestation Bundles bind signed mission authority to each execution step, Continuous Authority Revocation propagates termination signals across execution boundaries, and Decision Artifacts provide the structured record linking each action to the authority that governed it. The primitives align closely with the mandate service components described in this post and represent the closest published academic framework for execution-layer mission governance in AI agent systems. # ๐Ÿ”ฎ The Next Control Plane The gap was invisible because humans were closing it. Presence, pacing, and natural scope-limiting were doing governance work that no formal layer had to model. Agents remove all of that. When we hand execution to agents, we inherit the obligation to replace what humans provided implicitly. A governed mandate with a defined purpose, bounded scope, and a clear end. Agents are not the first systems to create this mismatch. Long-running workflows and autonomous integrations face the same dynamic. Agents are where it becomes impossible to ignore. The shift is structural. Request-scoped controls answer each boundary correctly and leave the mission ungoverned. The current stack has not needed a mission-scoped layer until now. This does not require discarding what works. [OAuth](https://oauth.net/2/), [OpenID Connect (OIDC)](https://openid.net/connect/), [Zero Trust](https://csrc.nist.gov/publications/detail/sp/800/207/final), and fine-grained authorization all remain foundational. What is missing is the layer above them that holds mission authority as a first-class, independently revocable artifact and governs whether execution should continue, independent of token validity. The four primitives described above are the components of that layer, each composing with what already exists. The mandate service sits above the authorization server, evaluation feeds existing PDPs, propagation runs over SSF/CAEP rails, and enforcement embeds in existing agent frameworks. When this layer exists, agents can be deployed at scale without choosing between control and utility. Authority can be delegated explicitly, constrained to purpose, and terminated cleanly when purpose expires. The blast radius of a compromised or runaway agent shrinks to the scope of its active mission rather than the full reach of its identity. > We spent the last decade building better ways to verify who is at the door. The next decade is about governing what they are authorized to do once they are inside. The security of the agentic enterprise depends on governing the stay, not just the entry. Identity controls establish who the agent is. Access controls govern what it may do at each boundary. The mandate layer governs whether the agent should still be acting at all. That is the missing primitive. These are its four components. And that is the next control plane. --- # About Canonical URL: https://notes.karlmcguinness.com/about/ Markdown URL: https://notes.karlmcguinness.com/about.md {{< profile-card src="/images/me.jpg" >}} I'm [Karl McGuinness](https://karlmcguinness.com), a product and technology leader with 25+ years of experience building mission-critical, internet-scale identity and infrastructure platforms. At Okta, I spent over a decade helping modern enterprises and the broader industry treat identity as foundational infrastructure. I specialize in product architecture, the intersection of product strategy and system design. I translate ambiguous requirements into durable product structures: domain boundaries, APIs, platform extensibility, and investment sequencing that keep teams fast today and options open later. This site, **Control Plane**, is where I work through the harder questions: not just how identity works today, but what it needs to become as autonomous agents, delegated authority, and machine-speed decisions replace the human-centric models we built everything on. ## Focus Areas - **Agentic identity**: how authentication and authorization must evolve as agents act on behalf of principals and operate without human supervision - **Governance and authority**: delegation chains and accountability structures that make autonomous systems trustworthy - **Trust and Identity infrastructure**: protocols, assertions, and verification mechanisms that let systems make access decisions with confidence - **Enterprise IAM**: SSO/Access Management, IGA, PAM and the interoperability gaps that still make enterprise identity harder than it should be ## Standards Work I contribute to standards that make identity systems interoperable in practice. - **IETF OAuth WG**: [ID-JAG](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/) and [OAuth Resource Parameter in Token Response](https://datatracker.ietf.org/doc/draft-mcguinness-oauth-resource-token-resp/) - **OpenID Foundation**: [Provider Commands 1.0](https://openid.github.io/openid-provider-commands/main.html), [OIDC Enterprise Extensions 1.0](https://openid.github.io/connect-enterprise-extensions/main.html), and [IPSIE](https://github.com/openid/ipsie) For full background, see [karlmcguinness.com](https://karlmcguinness.com). ## Background Before Okta, I worked across enterprise healthcare software, developer tools, and internet infrastructure. That cross-domain background is where my lens comes from: aligning product intent, architecture boundaries, and execution sequencing under real constraints. ## Get in Touch I work with teams on product architecture, identity strategy, and standards-informed design reviews. I also speak with product and engineering organizations on agentic identity, delegated authority, and trust infrastructure. [LinkedIn](https://www.linkedin.com/in/karlmcguinness) ยท [Email](mailto:public@karlmcguinness.com) ยท [GitHub](https://github.com/mcguinness) --- # Welcome to Control Plane Canonical URL: https://notes.karlmcguinness.com/notes/welcome-to-control-plane/ Markdown URL: https://notes.karlmcguinness.com/notes/welcome-to-control-plane.md Identity is getting weird again, and in a good way. This blog is where I post hot takes, field notes, and analysis on identity, security, and agentic systems. Some posts will be tactical. Some will be opinionated. Some will be me zooming out and asking, "are we solving the right problem at all?" Lately I keep coming back to one thing: most of our stack is great at deciding who can get in, and still pretty weak at governing what autonomous systems should keep doing over time. So expect writing on: - Identity and access patterns that hold up in real environments - Where agent security models break under real runtime conditions - Delegation, authority, and accountability across multi-hop systems - Standards progress, standards gaps, and implementation reality - The occasional spicy take when the industry starts hand-waving If you build or run identity and security systems, youโ€™re in the right place.