<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<!-- name="GENERATOR" content="github.com/mmarkdown/mmark Mmark Markdown Processor - mmark.miek.nl" -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" version="3" ipr="trust200902" docName="draft-hardt-aauth-protocol-01" submissionType="IETF" category="std" xml:lang="en" indexInclude="true">

<front>
<title abbrev="AAuth-Protocol">AAuth Protocol</title><seriesInfo value="draft-hardt-aauth-protocol-01" stream="IETF" status="standard" name="Internet-Draft"/>
<author initials="D." surname="Hardt" fullname="Dick Hardt"><organization>Hellō</organization><address><postal><street/>
</postal><email>dick.hardt@gmail.com</email>
</address></author><date/>
<area>Security</area>
<workgroup>TBD</workgroup>
<keyword>agent</keyword>
<keyword>authentication</keyword>
<keyword>authorization</keyword>
<keyword>http</keyword>
<keyword>signatures</keyword>

<abstract>
<t>This document defines the AAuth authorization protocol for agent-to-resource authorization and identity claim retrieval. The protocol supports four resource access modes — identity-based, resource-managed (two-party), PS-managed (three-party), and federated (four-party) — with agent governance as an orthogonal layer. It builds on the HTTP Signature Keys specification (<xref target="I-D.hardt-httpbis-signature-key"/>) for HTTP Message Signatures and key discovery.</t>
</abstract>

<note><name>Discussion Venues</name>
<t><em>Note: This section is to be removed before publishing as an RFC.</em></t>
<t>This document is part of the AAuth specification family. Source for this draft and an issue tracker can be found at <eref target="https://github.com/dickhardt/AAuth">https://github.com/dickhardt/AAuth</eref>.</t>
</note>

</front>

<middle>

<section anchor="introduction"><name>Introduction</name>

<section anchor="http-clients-need-their-own-identity"><name>HTTP Clients Need Their Own Identity</name>
<t>In OAuth 2.0 <xref target="RFC6749"/> and OpenID Connect <xref target="OpenID.Core"/>, the client has no independent identity. Client identifiers are issued by each authorization server or OpenID provider — a <tt>client_id</tt> at Google is meaningless at GitHub. The client's identity exists only in the context of each server it has pre-registered with. This made sense when the web had a manageable number of integrations and a human developer could visit each portal to register.</t>
<t>API keys are the same model pushed further: a shared secret issued by a service, copied to the client, and used as a bearer credential. The problem is that any secret that must be copied to where the workload runs will eventually be copied somewhere it shouldn't be.</t>
<t>SPIFFE and WIMSE brought workload identity to enterprise infrastructure — a workload can prove who it is without shared secrets. But these operate within a single enterprise's trust domain. They don't help an agent that needs to access resources across organizational boundaries, or a developer's tool that runs outside any enterprise platform.</t>
<t>AAuth starts from this premise: every agent has its own cryptographic identity. An agent identifier (<tt>aauth:local@domain</tt>) is bound to a signing key, published at a well-known URL, and verifiable by any party — no pre-registration, no shared secrets, no dependency on a particular server. At its simplest, an agent signs a request and a resource decides what to do based on who the agent is. This identity-based access replaces API keys and is the foundation that authorization, governance, and federation build on incrementally.</t>
</section>

<section anchor="agents-are-different"><name>Agents Are Different</name>
<t>Traditional software knows at build time what services it will call and what permissions it needs. Registration, key provisioning, and scope configuration happen before the first request. This works when the set of integrations is fixed and known in advance.</t>
<t>Agents don't work this way. They discover resources at runtime. They execute long-running tasks that span multiple services across trust domains. They need to explain what they're doing and why. They need authorization decisions mid-task, long after the user set them in motion. A protocol designed for pre-registered clients with fixed integrations cannot serve agents that discover their needs as they go.</t>
</section>

<section anchor="what-aauth-provides"><name>What AAuth Provides</name>

<ul spacing="compact">
<li><strong>Agent identity without pre-registration</strong>: A domain, static metadata, and a JWKS establish identity with no portal, no bilateral agreement, no shared secret.</li>
<li><strong>Per-instance identity</strong>: Each agent instance gets its own identifier (<tt>aauth:local@domain</tt>) and signing key.</li>
<li><strong>Proof-of-possession on every request</strong>: HTTP Message Signatures (<xref target="RFC9421"/>) bind every request to the agent's key — a stolen token is useless without the private key.</li>
<li><strong>Two-party mode with first-call registration</strong>: An agent calls a resource it has never contacted before; the resource returns <tt>AAuth-Requirement</tt>; a browser interaction handles account creation, payment, and consent. The first API call is the registration.</li>
<li><strong>Tool-call governance</strong>: A person server (PS) represents the user and manages what tools the agent can call, providing permission and audit for tool use — no resource involved.</li>
<li><strong>Missions</strong>: Optional scoped authorization contexts that span multiple resources. The agent proposes what it intends to do in natural language; the person server provides full context — mission, history, justification — to the appropriate decision-maker (human or AI); every resource access is evaluated in context. Missions enable governance over decisions that cannot be reduced to predefined machine-evaluable rules.</li>
<li><strong>Cross-domain federation</strong>: The PS federates with access servers (AS) — the policy engines that guard resources — to enable access across trust domains without the agent needing to know about each one.</li>
<li><strong>Clarification chat</strong>: Users can ask questions during consent; agents can explain or adjust their requests.</li>
<li><strong>Progressive adoption</strong>: Each party can adopt independently; modes build on each other.</li>
</ul>
</section>

<section anchor="what-aauth-does-not-do"><name>What AAuth Does Not Do</name>

<ul spacing="compact">
<li>Does not require centralized identity providers — agents publish their own identity</li>
<li>Does not use shared secrets or bearer tokens — every credential is bound to a signing key and useless without it</li>
<li>Does not require coordination to adopt — each party adds support independently</li>
</ul>
</section>

<section anchor="relationship-to-existing-standards"><name>Relationship to Existing Standards</name>
<t>AAuth builds on existing standards and design patterns:</t>

<ul spacing="compact">
<li><strong>OpenID Connect vocabulary</strong>: AAuth reuses OpenID Connect scope values, identity claims, and enterprise extensions (<xref target="OpenID.Enterprise"/>), lowering the adoption barrier for identity-aware resources.</li>
<li><strong>Well-known metadata and key discovery</strong>: Servers publish metadata at well-known URLs (<xref target="RFC8615"/>) and signing keys via JWKS endpoints, following the pattern established by OAuth Authorization Server Metadata (<xref target="RFC8414"/>) and OpenID Connect Discovery (<xref target="OpenID.Core"/>).</li>
<li><strong>HTTP Message Signatures</strong>: All requests are signed with HTTP Message Signatures (<xref target="RFC9421"/>) using keys bound to tokens conveyed via the Signature-Key header (<xref target="I-D.hardt-httpbis-signature-key"/>), providing proof-of-possession, identity, and message integrity on every call.</li>
</ul>
<t>The HTTP Signature Keys specification (<xref target="I-D.hardt-httpbis-signature-key"/>) defines how signing keys are bound to JWTs and discovered via well-known metadata, and how agents present cryptographic identity using HTTP Message Signatures (<xref target="RFC9421"/>). This specification defines the <tt>AAuth-Requirement</tt>, <tt>AAuth-Access</tt>, and <tt>AAuth-Capabilities</tt> headers, and the authorization protocol across four resource access modes.</t>
<t>Because agent identity is independent and self-contained, AAuth is designed for incremental adoption — each party can add support independently, and rollout does not need to be coordinated. A resource that verifies an agent's signature can manage access by identity alone, with no other infrastructure. When a resource manages its own authorization — via interaction, consent, or existing infrastructure — it operates in resource-managed access (two-party). Issuing resource tokens to the agent's person server enables PS-managed access (three-party), where auth tokens carry user identity, organization membership, and group information. Deploying an access server enables federated access (four-party) with cross-domain policy enforcement. Agent governance — missions, permissions, audit — is an orthogonal layer that any agent with a PS can add, from a simple prompt to full autonomous agent oversight. See <xref target="incremental-adoption"/> for details.</t>
</section>
</section>

<section anchor="conventions-and-definitions"><name>Conventions and Definitions</name>
<t>{::boilerplate bcp14-tagged}</t>
<t>In HTTP examples throughout this document, line breaks and indentation are added for readability. Actual HTTP messages do not contain these extra line breaks.</t>
</section>

<section anchor="terminology"><name>Terminology</name>
<t>Parties:</t>

<ul spacing="compact">
<li><strong>Person</strong>: A user or organization — the legal person — on whose behalf an agent acts and who is accountable for the agent's actions.</li>
<li><strong>Agent</strong>: An HTTP client (<xref target="RFC9110"/>, Section 3.5) acting on behalf of a person. Identified by an agent identifier URIs using the <tt>aauth</tt> scheme, of the form <tt>aauth:local@domain</tt> <xref target="agent-identifiers"/>. An agent MAY have a person server, declared via the <tt>ps</tt> claim in the agent token.</li>
<li><strong>Agent Server</strong>: A server that manages agent identity and issues agent tokens to agents. Trusted by the person to issue agent tokens only to authorized agents. Identified by an HTTPS URL <xref target="server-identifiers"/> and publishes metadata at <tt>/.well-known/aauth-agent.json</tt>.</li>
<li><strong>Resource</strong>: A server that requires authentication and/or authorization to protect access to its APIs and data. A resource MAY enforce access policy itself or delegate policy evaluation to an access server. Identified by an HTTPS URL <xref target="server-identifiers"/> and publishes metadata at <tt>/.well-known/aauth-resource.json</tt>. A mission-aware resource includes the mission object from the <tt>AAuth-Mission</tt> header in the resource tokens it issues.</li>
<li><strong>Person Server (PS)</strong>: A server that represents the person to the rest of the protocol. The person chooses their PS; it is not imposed by any other party. The PS manages missions, handles consent, asserts user identity, and brokers authorization on behalf of agents. Identified by an HTTPS URL <xref target="server-identifiers"/> and publishes metadata at <tt>/.well-known/aauth-person.json</tt>.</li>
<li><strong>Access Server (AS)</strong>: A policy engine that evaluates token requests, applies resource policy, and issues auth tokens on behalf of a resource. Identified by an HTTPS URL <xref target="server-identifiers"/> and publishes metadata at <tt>/.well-known/aauth-access.json</tt>.</li>
</ul>
<t>Tokens:</t>

<ul spacing="compact">
<li><strong>Agent Token</strong>: Issued by an agent server to establish the agent's identity. MAY declare the agent's person server <xref target="agent-tokens"/>.</li>
<li><strong>Resource Token</strong>: Issued by a resource to describe the access the agent needs <xref target="resource-tokens"/>.</li>
<li><strong>Auth Token</strong>: Issued by a PS or AS to grant an agent access to a resource, containing identity claims and/or authorized scopes <xref target="auth-tokens"/>.</li>
</ul>
<t>Protocol concepts:</t>

<ul spacing="compact">
<li><strong>Mission</strong>: A scoped authorization context for agent governance <xref target="missions"/>. Required when the person's PS requires governance over the agent's actions. A mission is a JSON object containing structured fields (approver, agent, approved_at, approved tools) and a Markdown description. Identified by the PS and SHA-256 hash of the mission JSON (<tt>s256</tt>). Missions are proposed by agents and approved by the PS and person.</li>
<li><strong>Mission Log</strong>: The ordered record of all agent↔PS interactions within a mission — token requests, permission requests, audit records, interaction requests, and clarification chats. The PS maintains the log and uses it to evaluate whether each new request is consistent with the mission's intent <xref target="mission-log"/>.</li>
<li><strong>HTTP Sig</strong>: An HTTP Message Signature (<xref target="RFC9421"/>) created per the AAuth HTTP Message Signatures profile defined in this specification <xref target="http-message-signatures-profile"/>, using a key conveyed via the <tt>Signature-Key</tt> header (<xref target="I-D.hardt-httpbis-signature-key"/>).</li>
<li><strong>Markdown</strong>: AAuth uses Markdown (<xref target="CommonMark"/>) as the human-readable content format for mission descriptions, justifications, clarifications, and scope descriptions. Implementations MUST sanitize Markdown before rendering to users.</li>
<li><strong>Interaction</strong>: User authentication, consent, or other action at an interaction endpoint <xref target="user-interaction"/>. Triggered when a server returns <tt>202 Accepted</tt> with <tt>requirement=interaction</tt>.</li>
<li><strong>Justification</strong>: A Markdown string provided by the agent declaring why access is needed, presented to the user by the PS during consent <xref target="ps-token-endpoint"/>.</li>
<li><strong>Clarification</strong>: A Markdown string containing a question posed to the agent by the user during consent via the PS <xref target="clarification-chat"/>. The agent may respond with an explanation or an updated request.</li>
</ul>
</section>

<section anchor="protocol-overview"><name>Protocol Overview</name>
<t>All AAuth tokens are JWTs verified using a JWK retrieved from the <tt>jwks_uri</tt> in the issuer's well-known metadata, binding each token to the server that issued it.</t>
<t>AAuth has two dimensions: <strong>resource access modes</strong> and <strong>agent governance</strong>. Resource access modes define how an agent gets authorized at a resource. Agent governance — missions, permissions, audit — is an orthogonal layer that any agent with a person server can add, independent of which access mode the resource supports.</t>

<section anchor="resource-access-modes"><name>Resource Access Modes</name>
<t>AAuth supports four resource access modes, each adding parties and capabilities. The protocol works in every mode — adoption does not require coordination between parties.</t>
<table>
<thead>
<tr>
<th>Mode</th>
<th>Parties</th>
<th>Description</th>
</tr>
</thead>

<tbody>
<tr>
<td>Identity-based access</td>
<td>Agent <br/>
 Resource</td>
<td>Resource verifies agent's signed identity and applies its own access control</td>
</tr>

<tr>
<td>Resource-managed access <br/>
(two-party)</td>
<td>Agent <br/>
 Resource</td>
<td>Resource manages authorization with interaction, consent, or existing auth infrastructure</td>
</tr>

<tr>
<td>PS-managed access <br/>
(three-party)</td>
<td>Agent <br/>
 Resource <br/>
 PS</td>
<td>Resource issues resource token to PS; <br/>
 PS issues auth token</td>
</tr>

<tr>
<td>Federated access <br/>
(four-party)</td>
<td>Agent <br/>
 Resource <br/>
 PS <br/>
 AS</td>
<td>Resource has its own access server; <br/>
 PS federates with AS</td>
</tr>
</tbody>
</table><t>The following diagram shows all parties and their relationships. Not all parties or relationships are present in every mode.</t>
<figure anchor="fig-parties"><name>Protocol Parties and Relationships </name>
<sourcecode type="ascii-art"><![CDATA[                     +--------------+
                     |    Person    |
                     +--------------+
                      ^           ^
              mission |           | consent
                      v           v
                     +--------------+    federation    +--------------+
                     |              |----------------->|              |
                     |   Person     |                  |   Access     |
                     |   Server     |<-----------------|   Server     |
                     |              |    auth token    |              |
                     +--------------+                  +--------------+
                      ^          ^ |
            mission   | resource | | auth
                      |    token | | token
                      |          | v
              agent  +--------------+  signed request  +--------------+
+-----------+ token  |              |----------------->|              |
|   Agent   |------->|    Agent     |                  |   Resource   |
|   Server  |        |              |<-----------------|              |
+-----------+        +--------------+     resource     +--------------+

]]>
</sourcecode>
</figure>

<ul spacing="compact">
<li><strong>Agent Server → Agent</strong>: Issues an agent token binding the agent's signing key to its identity.</li>
<li><strong>Agent ↔ Resource</strong>: Agent sends signed requests; resource returns responses. In PS-managed and federated modes, the resource also returns resource tokens at its authorization endpoint.</li>
<li><strong>Agent ↔ PS</strong>: Agent sends resource tokens to obtain auth tokens. With governance, agent also creates missions and requests permissions.</li>
<li><strong>PS ↔ AS</strong>: Federation (four-party only). The PS sends the resource token to the AS; the AS returns an auth token.</li>
<li><strong>Person ↔ PS</strong>: Mission approval and consent for resource access.</li>
</ul>
<t>Detailed end-to-end flows are in <xref target="detailed-flows"/>. The following subsections describe each mode.</t>

<section anchor="overview-identity-access"><name>Identity-Based Access</name>
<t>The agent signs requests with its agent token <xref target="agent-tokens"/>. The resource verifies the agent's identity via HTTP signatures and applies its own access control policy — granting or denying based on who the agent is. This replaces API keys with cryptographic identity. No authorization flow, no tokens beyond the agent token.</t>
<figure anchor="fig-identity-access"><name>Identity-Based Access </name>
<sourcecode type="ascii-art"><![CDATA[Agent                                        Resource
  |                                             |
  | HTTPSig w/ agent token                      |
  |-------------------------------------------->|
  |                                             |
  | 200 OK                                      |
  |<--------------------------------------------|
]]>
</sourcecode>
</figure>
</section>

<section anchor="overview-resource-managed"><name>Resource-Managed Access (Two-Party)</name>
<t>The resource handles authorization itself — via interaction <xref target="user-interaction"/>, existing OAuth/OIDC infrastructure, or internal policy. After authorization, the resource MAY return an <tt>AAuth-Access</tt> header <xref target="aauth-access"/> with an opaque access token for subsequent calls.</t>
<figure anchor="fig-resource-managed"><name>Resource-Managed Access (Two-Party) </name>
<sourcecode type="ascii-art"><![CDATA[Agent                                        Resource
  |                                             |
  | HTTPSig w/ agent token                      |
  |-------------------------------------------->|
  |                                             |
  | 202 (interaction required)                  |
  |<--------------------------------------------|
  |                                             |
  | [user completes interaction]                |
  |                                             |
  | GET pending URL                             |
  |-------------------------------------------->|
  |                                             |
  | 200 OK                                      |
  | AAuth-Access: opaque-token                  |
  |<--------------------------------------------|
  |                                             |
  | HTTPSig w/ agent token                      |
  | Authorization: AAuth opaque-token           |
  |-------------------------------------------->|
  |                                             |
  | 200 OK                                      |
  |<--------------------------------------------|
]]>
</sourcecode>
</figure>
</section>

<section anchor="ps-managed-access-three-party"><name>PS-Managed Access (Three-Party)</name>
<t>The resource discovers the agent's PS from the <tt>ps</tt> claim in the agent token and issues a resource token <xref target="resource-tokens"/> with <tt>aud</tt> = PS URL. The agent obtains the resource token either by calling the resource's <tt>authorization_endpoint</tt> (if published in resource metadata) or by receiving a <tt>401</tt> challenge with <tt>requirement=auth-token</tt> when calling the resource directly <xref target="requirement-auth-token"/>. The agent sends the resource token to the PS's token endpoint <xref target="ps-token-endpoint"/>, and the PS issues an auth token <xref target="auth-tokens"/> directly. The auth token can carry user identity, organization membership, and group information — enabling the resource to get rich authorization context from the PS without building its own identity infrastructure.</t>
<figure anchor="fig-ps-managed"><name>PS-Managed Access (Three-Party) </name>
<sourcecode type="ascii-art"><![CDATA[Agent                                 Resource       PS
  |                                      |            |
  | HTTPSig w/ agent token               |            |
  | POST authorization_endpoint          |            |
  |------------------------------------->|            |
  |                                      |            |
  | resource_token (aud = PS URL)        |            |
  |<-------------------------------------|            |
  |                                      |            |
  | HTTPSig w/ agent token               |            |
  | POST token_endpoint                  |            |
  | w/ resource_token                    |            |
  |-------------------------------------------------->|
  |                                      |            |
  | auth_token                           |            |
  |<--------------------------------------------------|
  |                                      |            |
  | HTTPSig w/ auth token                |            |
  | GET /api/documents                   |            |
  |------------------------------------->|            |
  |                                      |            |
  | 200 OK                               |            |
  |<-------------------------------------|            |
]]>
</sourcecode>
</figure>
</section>

<section anchor="federated-access-four-party"><name>Federated Access (Four-Party)</name>
<t>The resource has its own access server. The resource issues a resource token <xref target="resource-tokens"/> with <tt>aud</tt> = AS URL — either via its <tt>authorization_endpoint</tt> or a <tt>401</tt> challenge <xref target="requirement-auth-token"/>. The PS federates with the AS <xref target="ps-as-federation"/> to obtain the auth token <xref target="auth-tokens"/>.</t>
<figure anchor="fig-federated"><name>Federated Access (Four-Party) </name>
<sourcecode type="ascii-art"><![CDATA[Agent                                Resource   PS                    AS
  |                                     |       |                      |
  | HTTPSig w/ agent token              |       |                      |
  | POST authorization_endpoint         |       |                      |
  |------------------------------------>|       |                      |
  |                                     |       |                      |
  | resource_token (aud = AS URL)       |       |                      |
  |<------------------------------------|       |                      |
  |                                     |       |                      |
  | HTTPSig w/ agent token              |       |                      |
  | POST token_endpoint                 |       |                      |
  | w/ resource_token                   |       |                      |
  |-------------------------------------------->|                      |
  |                                     |       |                      |
  |                                     |       | HTTPSig w/ jwks_uri  |
  |                                     |       | POST token_endpoint  |
  |                                     |       | w/ resource_token    |
  |                                     |       |--------------------->|
  |                                     |       |                      |
  |                                     |       | auth_token           |
  |                                     |       |<---------------------|
  |                                     |       |                      |
  | auth_token                          |       |                      |
  |<--------------------------------------------|                      |
  |                                     |       |                      |
  | HTTPSig w/ auth token               |       |                      |
  | GET /api/documents                  |       |                      |
  |------------------------------------>|       |                      |
  |                                     |       |                      |
  | 200 OK                              |       |                      |
  |<------------------------------------|       |                      |
]]>
</sourcecode>
</figure>
</section>

<section anchor="agent-server-as-resource"><name>Agent Server as Resource</name>
<t>An agent server MAY also act as a resource — publishing metadata at <tt>/.well-known/aauth-resource.json</tt> and issuing resource tokens. This enables the agent to obtain auth tokens from its PS for the agent server's own services or infrastructure, using the standard resource token flow. How the agent obtains the resource token from the agent server is out of scope of this specification. No mission is required.</t>
</section>
</section>

<section anchor="agent-governance"><name>Agent Governance</name>
<t>Agent governance is orthogonal to resource access modes. Any agent with a person server (<tt>ps</tt> claim in agent token) can use the PS for governance, regardless of which access modes the resources it accesses support.</t>

<section anchor="missions-overview"><name>Missions</name>
<t>When the person's PS requires governance over the agent's actions, the agent creates a mission — a Markdown description of what it intends to accomplish. The PS and user review, clarify, and approve the mission. The approved mission is immutable — bound by its <tt>s256</tt> hash. Missions evolve through the <strong>mission log</strong> <xref target="mission-log"/>: the ordered record of all agent↔PS interactions within the mission. Missions are not required for all PS interactions — an agent can get auth tokens without a mission. See <xref target="missions"/> for normative requirements.</t>

<section anchor="mission-creation"><name>Mission Creation</name>
<t>The agent proposes a mission at the PS. The PS and user may clarify and refine before approving.</t>
<figure anchor="fig-mission"><name>Mission Creation and Approval </name>
<sourcecode type="ascii-art"><![CDATA[Agent                                     PS                        User
  |                                        |                          |
  | HTTPSig w/ agent token                 |                          |
  | POST mission_endpoint                  |                          |
  | proposal                               |                          |
  |--------------------------------------->|                          |
  |                                        |                          |
  | [clarification chat]                   | review, clarify, approve |
  |<-------------------------------------->|<------------------------>|
  |                                        |                          |
  | 200 OK                                 |                          |
  | AAuth-Mission: approver=...; s256=...  |                          |
  | {mission blob}                         |                          |
  |<---------------------------------------|                          |
]]>
</sourcecode>
</figure>
</section>

<section anchor="mission-context-at-resources"><name>Mission Context at Resources</name>
<t>The agent includes the <tt>AAuth-Mission</tt> header when sending requests to resources, unless the mission is already conveyed in an auth token. The resource includes the mission object in the resource token it issues:</t>
<figure anchor="fig-mission-context"><name>Mission Context at Resource </name>
<sourcecode type="ascii-art"><![CDATA[Agent                                        Resource
  |                                             |
  | HTTPSig w/ agent token                      |
  | AAuth-Mission: approver=...; s256=...       |
  | POST authorization_endpoint                 |
  |-------------------------------------------->|
  |                                             |
  | resource_token                              |
  | (mission object included)                   |
  |<--------------------------------------------|
]]>
</sourcecode>
</figure>
</section>

<section anchor="mission-completion"><name>Mission Completion</name>
<t>When the agent believes the mission is complete, it proposes completion via the interaction endpoint with a summary. The PS presents the summary to the user. The user either accepts (mission terminates) or responds with follow-up questions (mission continues).</t>
<figure anchor="fig-mission-completion"><name>Mission Completion </name>
<sourcecode type="ascii-art"><![CDATA[Agent                                     PS                        User
  |                                        |                          |
  | HTTPSig w/ agent token                 |                          |
  | POST interaction_endpoint              |                          |
  | type=completion, summary               |                          |
  |--------------------------------------->|                          |
  |                                        |                          |
  |                                        | present summary          |
  |                                        |------------------------->|
  |                                        |                          |
  |                                        | accept / follow-up       |
  |                                        |<-------------------------|
  |                                        |                          |
  | 200 OK (terminated)                    |                          |
  | or clarification (continues)           |                          |
  |<---------------------------------------|                          |
]]>
</sourcecode>
</figure>
</section>
</section>

<section anchor="ps-governance-endpoints"><name>PS Governance Endpoints</name>
<t>The PS provides three governance endpoints. The <strong>permission</strong> <xref target="permission-endpoint"/> and <strong>interaction</strong> <xref target="interaction-endpoint"/> endpoints work with or without a mission. The <strong>audit</strong> endpoint <xref target="audit-endpoint"/> requires a mission.</t>

<ul spacing="compact">
<li><strong>Permission endpoint</strong>: Request permission for actions not governed by a remote resource — tool calls, file writes, sending messages.</li>
<li><strong>Audit endpoint</strong>: Log actions performed, providing the PS with a complete record for the mission log.</li>
<li><strong>Interaction endpoint</strong>: Reach the user through the PS — relay interactions, ask questions, forward payment approvals, or propose mission completion.</li>
</ul>
</section>
</section>

<section anchor="obtaining-an-agent-token"><name>Obtaining an Agent Token</name>
<t>The agent obtains an agent token from its agent server. The agent generates a signing key pair, proves its identity to the agent server through a platform-specific mechanism, and receives an agent token binding the signing key to the agent's identifier. The agent token MAY include a <tt>ps</tt> claim identifying the agent's person server. Agent token acquisition is platform-dependent — see <xref target="agent-token-acquisition"/> for common patterns and <xref target="agent-tokens"/> for token structure and normative requirements.</t>
</section>

<section anchor="bootstrapping"><name>Bootstrapping</name>
<t>Before protocol flows begin, each entity must be established with its identity, keys, and relationships. The requirements build incrementally.</t>
<t><strong>All modes:</strong></t>

<ul spacing="compact">
<li>Agent obtains an agent token from its agent server, binding its signing key to its identifier (<tt>aauth:local@domain</tt>). See <xref target="agent-token-acquisition"/>.</li>
<li>Agent servers publish metadata at <tt>/.well-known/aauth-agent.json</tt> <xref target="agent-server-metadata"/>.</li>
</ul>
<t><strong>Resource-managed access (two-party) and above:</strong></t>

<ul spacing="compact">
<li>Resources MAY publish metadata at <tt>/.well-known/aauth-resource.json</tt> <xref target="resource-metadata"/>. Resources that do not publish metadata can still issue resource tokens and interaction requirements via <tt>401</tt> responses.</li>
</ul>
<t><strong>PS-managed access (three-party) and above:</strong></t>

<ul spacing="compact">
<li>The agent's agent token includes the <tt>ps</tt> claim identifying its person server. This is configured during agent setup (e.g., set by the agent server or chosen by the person deploying the agent).</li>
<li>The PS maintains the association between an agent and its person. This association is typically established when the person first authorizes the agent at the PS via the interaction flow. An organization administrator may also pre-authorize agents for the organization.</li>
<li>The PS MAY establish a direct communication channel with the user (e.g., email, push notification, or messaging) to support out-of-band authorization, approval notifications, and revocation alerts.</li>
<li>Person servers publish metadata at <tt>/.well-known/aauth-person.json</tt> <xref target="ps-metadata"/>.</li>
<li>The resource discovers the agent's PS from the <tt>ps</tt> claim in the agent token and issues resource tokens with <tt>aud</tt> = PS URL.</li>
</ul>
<t><strong>Federated access (four-party):</strong></t>

<ul spacing="compact">
<li>Access servers publish metadata at <tt>/.well-known/aauth-access.json</tt> <xref target="access-server-metadata"/>.</li>
<li>The resource issues resource tokens with <tt>aud</tt> = AS URL.</li>
<li>The PS and the resource's AS must have a trust relationship before the AS will issue auth tokens. This trust may be pre-established (through a business relationship) or established dynamically through the AS's token endpoint responses — interaction, payment, or claims. When an organization controls both the PS and AS, trust is implicit. See <xref target="ps-as-federation"/> for details.</li>
</ul>
</section>
</section>

<section anchor="agent-identity"><name>Agent Identity</name>
<t>This section defines agent identity — how agents are identified and how that identity is bound to signing keys via agent tokens. Agent identity is the foundation of AAuth: every signed request an agent makes carries its agent token, enabling any party to verify who the agent is and that the request was signed by the key bound to that identity.</t>

<section anchor="agent-identifiers"><name>Agent Identifiers</name>
<t>Agent identifiers are URIs using the <tt>aauth</tt> scheme, of the form <tt>aauth:local@domain</tt> where <tt>domain</tt> is the agent server's domain. The <tt>local</tt> part MUST consist of lowercase ASCII letters (<tt>a-z</tt>), digits (<tt>0-9</tt>), hyphen (<tt>-</tt>), underscore (<tt>_</tt>), plus (<tt>+</tt>), and period (<tt>.</tt>). The <tt>local</tt> part MUST NOT be empty and MUST NOT exceed 255 characters. The <tt>domain</tt> part MUST be a valid domain name conforming to the server identifier requirements <xref target="server-identifiers"/> (without scheme).</t>
<t>Valid agent identifiers:</t>

<ul spacing="compact">
<li><tt>aauth:assistant-v2@agent.example</tt></li>
<li><tt>aauth:cli+instance.1@tools.example</tt></li>
</ul>
<t>Invalid agent identifiers:</t>

<ul spacing="compact">
<li><tt>My Agent@agent.example</tt> (uppercase letters and space in local part)</li>
<li><tt>@agent.example</tt> (empty local part)</li>
<li><tt>agent@http://agent.example</tt> (domain includes scheme)</li>
</ul>
<t>Implementations MUST perform exact string comparison on agent identifiers (case-sensitive).</t>
</section>

<section anchor="agent-tokens"><name>Agent Token</name>

<section anchor="agent-token-acquisition-overview"><name>Agent Token Acquisition</name>
<t>An agent MUST obtain an agent token from its agent server before participating in the AAuth protocol. The acquisition process follows these steps:</t>

<ol spacing="compact">
<li>The agent generates an ephemeral signing key pair (EdDSA is RECOMMENDED).</li>
<li>The agent proves its identity to the agent server through a platform-specific mechanism.</li>
<li>The agent server verifies the agent's identity and issues an agent token binding the agent's ephemeral public key to the agent's identifier.</li>
</ol>
<t>The mechanism for proving identity is platform-dependent. See <xref target="agent-token-acquisition"/> for common patterns including server workloads (platform attestation), mobile applications (app attestation), desktop and CLI applications (user login or managed desktop attestation), and browser-based applications (WebAuthn).</t>
</section>

<section anchor="agent-token-structure"><name>Agent Token Structure</name>
<t>An agent token is a JWT with <tt>typ: aa-agent+jwt</tt> containing:</t>
<t>Header:
- <tt>alg</tt>: Signing algorithm. EdDSA is RECOMMENDED. Implementations MUST NOT accept <tt>none</tt>.
- <tt>typ</tt>: <tt>aa-agent+jwt</tt>
- <tt>kid</tt>: Key identifier</t>
<t>Required payload claims:
- <tt>iss</tt>: Agent server URL
- <tt>dwk</tt>: <tt>aauth-agent.json</tt> — the well-known metadata document name for key discovery (<xref target="I-D.hardt-httpbis-signature-key"/>)
- <tt>sub</tt>: Agent identifier (stable across key rotations)
- <tt>jti</tt>: Unique token identifier for replay detection, audit, and revocation
- <tt>cnf</tt>: Confirmation claim (<xref target="RFC7800"/>) with <tt>jwk</tt> containing the agent's public key
- <tt>iat</tt>: Issued at timestamp
- <tt>exp</tt>: Expiration timestamp. Agent tokens SHOULD NOT have a lifetime exceeding 24 hours.</t>
<t>Optional payload claims:
- <tt>ps</tt>: The HTTPS URL of the agent's person server. Configured per agent instance. When present, resources can discover the agent's PS from the agent token. This claim is distinct from <tt>iss</tt> (which identifies the agent server that issued the token).</t>
<t>Agent servers MAY include additional claims in the agent token. Companion specifications may define additional claims for use by PSes or ASes in policy evaluation — for example, software attestation, platform integrity, secure enclave status, workload identity assertions, or software publisher identity. PSes and ASes MUST ignore unrecognized claims.</t>
</section>

<section anchor="agent-token-usage"><name>Agent Token Usage</name>
<t>Agents present agent tokens via the <tt>Signature-Key</tt> header (<xref target="I-D.hardt-httpbis-signature-key"/>) using <tt>scheme=jwt</tt>:</t>

<sourcecode type="http"><![CDATA[Signature-Key: sig=jwt;
    jwt="eyJhbGciOiJFZERTQSIsInR5cCI6Im..."
]]>
</sourcecode>
</section>

<section anchor="agent-token-verification"><name>Agent Token Verification</name>
<t>Verify the agent token per <xref target="RFC7515"/> and <xref target="RFC7519"/>:</t>

<ol spacing="compact">
<li>Decode the JWT header. Verify <tt>typ</tt> is <tt>aa-agent+jwt</tt>.</li>
<li>Verify <tt>dwk</tt> is <tt>aauth-agent.json</tt>. Discover the issuer's JWKS via <tt>{iss}/.well-known/{dwk}</tt> per the HTTP Signature Keys specification (<xref target="I-D.hardt-httpbis-signature-key"/>). Locate the key matching the JWT header <tt>kid</tt> and verify the JWT signature.</li>
<li>Verify <tt>exp</tt> is in the future and <tt>iat</tt> is not in the future.</li>
<li>Verify <tt>iss</tt> is a valid HTTPS URL conforming to the Server Identifier requirements.</li>
<li>Verify <tt>cnf.jwk</tt> matches the key used to sign the HTTP request.</li>
<li>If <tt>ps</tt> is present, verify it is a valid HTTPS URL conforming to the Server Identifier requirements.</li>
</ol>
</section>
</section>
</section>

<section anchor="resource-tokens"><name>Resource Access and Resource Tokens</name>
<t>This section defines how agents request access to resources and how resources issue resource tokens.</t>
<t>A resource token can be returned in two ways:</t>

<ol spacing="compact">
<li><strong>Authorization endpoint</strong>: The agent proactively requests access at the resource's <tt>authorization_endpoint</tt>. The resource responds with a resource token.</li>
<li><strong>AAuth-Requirement challenge</strong>: The agent calls a resource endpoint directly. If the agent lacks sufficient authorization, the resource returns <tt>401</tt> with an <tt>AAuth-Requirement</tt> header containing a resource token <xref target="requirement-auth-token"/>.</li>
</ol>
<t>A resource MAY return a <tt>401</tt> with <tt>AAuth-Requirement</tt> even when the agent presents a valid auth token — for example, when the endpoint requires additional scopes or a different authorization context beyond what the current auth token grants (nested authorization).</t>
<t>A resource token is a signed JWT that cryptographically binds the resource's identity, the agent's identity, and the requested scope. The resource sets the token's audience based on its configuration:</t>

<ul spacing="compact">
<li>If the resource has its own AS: <tt>aud</tt> = AS URL (four-party)</li>
<li>If the resource has no AS but the agent has a PS (<tt>ps</tt> claim in agent token): <tt>aud</tt> = PS URL (three-party)</li>
<li>If neither: the resource handles authorization itself — via an interaction response <xref target="user-interaction"/> or internal policy — and MAY return an <tt>AAuth-Access</tt> header <xref target="aauth-access"/></li>
</ul>
<t>A resource MAY always handle authorization itself, regardless of whether the agent has a PS.</t>

<section anchor="authorization-endpoint-request"><name>Authorization Endpoint Request</name>
<t>A resource MAY publish an <tt>authorization_endpoint</tt> in its metadata. The agent sends a signed POST to the authorization endpoint. The resource reads the agent token from the <tt>Signature-Key</tt> header and determines how to respond — it may return a resource token, handle authorization itself, or both.</t>
<t><strong>Request parameters:</strong></t>

<ul spacing="compact">
<li><tt>scope</tt> (REQUIRED): A space-separated string of scope values the agent is requesting.</li>
</ul>

<sourcecode type="http"><![CDATA[POST /authorize HTTP/1.1
Host: resource.example
Content-Type: application/json
Signature-Input: sig=("@method" "@authority"
    "@path" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "scope": "data.read data.write"
}
]]>
</sourcecode>
<t>When the agent is operating in a mission context, it includes the <tt>AAuth-Mission</tt> header and adds <tt>aauth-mission</tt> to the signed components:</t>

<sourcecode type="http"><![CDATA[POST /authorize HTTP/1.1
Host: resource.example
Content-Type: application/json
AAuth-Mission:
    approver="https://ps.example";
    s256="dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
Signature-Input: sig=("@method" "@authority"
    "@path" "signature-key"
    "aauth-mission");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "scope": "data.read data.write"
}
]]>
</sourcecode>
</section>

<section anchor="authorization-endpoint-responses"><name>Authorization Endpoint Responses</name>
<t>The resource can handle authorization itself, or it can issue a resource token when the resource has an AS or the agent token includes a <tt>ps</tt> claim.</t>

<section anchor="response-without-resource-token"><name>Response without Resource Token</name>
<t>The resource handles authorization itself. It evaluates the request and returns a deferred response if user interaction is needed:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 202 Accepted
Location: https://resource.example/authorize/pending/abc123
Retry-After: 0
Cache-Control: no-store
AAuth-Requirement: requirement=interaction;
    url="https://resource.example/interaction"; code="A1B2-C3D4"
Content-Type: application/json

{
  "status": "pending"
}
]]>
</sourcecode>
<t>The user completes interaction at the resource's own consent page. The agent polls the <tt>Location</tt> URL. When authorization is complete, the resource returns <tt>200 OK</tt> and MAY include an <tt>AAuth-Access</tt> header <xref target="aauth-access"/> containing an opaque access token for subsequent calls.</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 200 OK
AAuth-Access: wrapped-opaque-token-value
Content-Type: application/json

{
  "status": "authorized",
  "scope": "data.read data.write"
}
]]>
</sourcecode>
<t>If the resource can authorize immediately (e.g., the agent's key is already authorized), it returns <tt>200 OK</tt> directly with the optional <tt>AAuth-Access</tt> header.</t>
</section>

<section anchor="response-with-resource-token"><name>Response with Resource Token</name>
<t>Alternatively, the resource MAY return a resource token. The resource sets the <tt>aud</tt> claim based on its configuration:</t>

<ul spacing="compact">
<li>If the resource has its own AS: <tt>aud</tt> = AS URL (four-party)</li>
<li>If the resource has no AS but the agent has a PS (<tt>ps</tt> claim): <tt>aud</tt> = PS URL (three-party)</li>
</ul>
<t>When the <tt>AAuth-Mission</tt> header is present, the resource includes the mission object (<tt>approver</tt> and <tt>s256</tt>) in the resource token.</t>

<sourcecode type="json"><![CDATA[{
  "resource_token": "eyJhbGc..."
}
]]>
</sourcecode>
<t>The agent sends the resource token to its PS's token endpoint.</t>
</section>

<section anchor="authorization-endpoint-error-responses"><name>Authorization Endpoint Error Responses</name>
<table>
<thead>
<tr>
<th>Error</th>
<th>Status</th>
<th>Meaning</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>invalid_request</tt></td>
<td>400</td>
<td>Missing or invalid parameters</td>
</tr>

<tr>
<td><tt>invalid_signature</tt></td>
<td>401</td>
<td>HTTP signature verification failed</td>
</tr>

<tr>
<td><tt>invalid_scope</tt></td>
<td>400</td>
<td>Requested scope not recognized by the resource</td>
</tr>

<tr>
<td><tt>server_error</tt></td>
<td>500</td>
<td>Internal error</td>
</tr>
</tbody>
</table><t>Error responses use the same format as the token endpoint <xref target="error-response-format"/>.</t>
</section>
</section>

<section anchor="aauth-access"><name>AAuth-Access Response Header</name>
<t>The <tt>AAuth-Access</tt> response header carries an opaque access token from a resource to an agent. The token is opaque to the agent — the resource wraps its internal authorization state (which MAY be an existing OAuth access token or other credential). The agent passes the token back to the resource via the <tt>Authorization</tt> header on subsequent requests:</t>

<sourcecode type="http"><![CDATA[GET /api/data HTTP/1.1
Host: resource.example
Authorization: AAuth wrapped-opaque-token-value
Signature-Input: sig=("@method" "@authority" "@path" \
    "authorization" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."
]]>
</sourcecode>
<t>The agent MUST include <tt>authorization</tt> in the covered components of its HTTP signature, binding the access token to the signed request. This prevents the token from being stolen and replayed as a standalone bearer token — the token is useless without a valid AAuth signature from the agent.</t>
<t>A resource MAY return a new <tt>AAuth-Access</tt> header on any response, replacing the agent's current access token. This enables rolling refresh without an explicit refresh flow. When the agent receives a new <tt>AAuth-Access</tt> value, it MUST use the new value on subsequent requests.</t>
</section>

<section anchor="resource-managed-auth"><name>Resource-Managed Authorization</name>
<t>When a resource manages authorization itself and requires user interaction, it returns a <tt>202 Accepted</tt> response with an interaction requirement:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 202 Accepted
Location: https://resource.example/pending/abc123
Retry-After: 0
Cache-Control: no-store
AAuth-Requirement: requirement=interaction;
    url="https://resource.example/interaction"; code="A1B2-C3D4"
Content-Type: application/json

{
  "status": "pending"
}
]]>
</sourcecode>
<t>The agent directs the user to the interaction URL <xref target="user-interaction"/> and polls the <tt>Location</tt> URL per the deferred response pattern <xref target="deferred-responses"/>. When the interaction completes, the resource returns <tt>200 OK</tt> and MAY include an <tt>AAuth-Access</tt> header <xref target="aauth-access"/> with an opaque access token for subsequent calls.</t>
<t>A resource MAY also authorize the agent based solely on its identity (from the agent token) without any interaction — for example, when the agent's key is already known or the agent's domain is trusted.</t>
</section>

<section anchor="requirement-auth-token"><name>Auth Token Required</name>
<t>A resource MUST use <tt>requirement=auth-token</tt> with a <tt>401 Unauthorized</tt> response when an auth token is required. The header MUST include a <tt>resource-token</tt> parameter containing a resource token JWT <xref target="resource-token-structure"/>.</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 401 Unauthorized
AAuth-Requirement: requirement=auth-token; resource-token="eyJ..."
]]>
</sourcecode>
<t>The agent MUST extract the <tt>resource-token</tt> parameter, verify the resource token <xref target="resource-challenge-verification"/>, and present it to its PS's token endpoint to obtain an auth token <xref target="ps-token-endpoint"/>. A resource MAY also use <tt>402 Payment Required</tt> with the same <tt>AAuth-Requirement</tt> header when payment is additionally required <xref target="requirement-responses"/>.</t>
<t>A resource MAY return <tt>requirement=auth-token</tt> with a new resource token to a request that already includes an auth token — for example, when the request requires a higher level of authorization than the current token provides. Agents MUST be prepared for this step-up authorization at any time.</t>
</section>

<section anchor="resource-token"><name>Resource Token</name>

<section anchor="resource-token-structure"><name>Resource Token Structure</name>
<t>A resource token is a JWT with <tt>typ: aa-resource+jwt</tt> containing:</t>
<t>Header:
- <tt>alg</tt>: Signing algorithm. EdDSA is RECOMMENDED. Implementations MUST NOT accept <tt>none</tt>.
- <tt>typ</tt>: <tt>aa-resource+jwt</tt>
- <tt>kid</tt>: Key identifier</t>
<t>Payload:
- <tt>iss</tt>: Resource URL
- <tt>dwk</tt>: <tt>aauth-resource.json</tt> — the well-known metadata document name for key discovery (<xref target="I-D.hardt-httpbis-signature-key"/>)
- <tt>aud</tt>: Token audience — the PS URL (when the resource delegates authorization to the agent's PS) or the AS URL (when the resource has its own access server)
- <tt>jti</tt>: Unique token identifier for replay detection, audit, and revocation
- <tt>agent</tt>: Agent identifier
- <tt>agent_jkt</tt>: JWK Thumbprint (<xref target="RFC7638"/>) of the agent's current signing key
- <tt>iat</tt>: Issued at timestamp
- <tt>exp</tt>: Expiration timestamp
- <tt>scope</tt>: Requested scopes, as a space-separated string of scope values. Companion specifications MAY define alternative authorization claims that replace <tt>scope</tt>.</t>
<t>Optional payload claims:
- <tt>mission</tt>: Mission object (present when the resource is mission-aware and the agent sent an <tt>AAuth-Mission</tt> header). Contains:
  - <tt>approver</tt>: HTTPS URL of the entity that approved the mission
  - <tt>s256</tt>: SHA-256 hash of the approved mission JSON (base64url)</t>
<t>Resource tokens SHOULD NOT have a lifetime exceeding 5 minutes. The <tt>jti</tt> claim provides an audit trail for token requests; ASes are not required to enforce replay detection on resource tokens. If a resource token expires before the PS presents it to the AS (e.g., because user interaction was required), the agent MUST obtain a fresh resource token from the resource and submit a new token request to the PS. The PS SHOULD remember prior consent decisions within a mission so the user is not re-prompted when the agent resubmits a request for the same resource and scope.</t>
</section>

<section anchor="resource-token-verification"><name>Resource Token Verification</name>
<t>Verify the resource token per <xref target="RFC7515"/> and <xref target="RFC7519"/>:</t>

<ol spacing="compact">
<li>Decode the JWT header. Verify <tt>typ</tt> is <tt>aa-resource+jwt</tt>.</li>
<li>Verify <tt>dwk</tt> is <tt>aauth-resource.json</tt>. Discover the issuer's JWKS via <tt>{iss}/.well-known/{dwk}</tt> per the HTTP Signature Keys specification (<xref target="I-D.hardt-httpbis-signature-key"/>). Locate the key matching the JWT header <tt>kid</tt> and verify the JWT signature.</li>
<li>Verify <tt>exp</tt> is in the future and <tt>iat</tt> is not in the future.</li>
<li>Verify <tt>aud</tt> matches the recipient's own identifier (the PS in three-party, or the AS in four-party).</li>
<li>Verify <tt>agent</tt> matches the requesting agent's identifier.</li>
<li>Verify <tt>agent_jkt</tt> matches the JWK Thumbprint of the key used to sign the HTTP request.</li>
<li>If <tt>mission</tt> is present, verify <tt>mission.approver</tt> matches the PS that sent the token request.</li>
</ol>
</section>

<section anchor="resource-challenge-verification"><name>Resource Challenge Verification</name>
<t>When an agent receives a <tt>401</tt> response with <tt>AAuth-Requirement: requirement=auth-token</tt>:</t>

<ol spacing="compact">
<li>Extract the <tt>resource-token</tt> parameter.</li>
<li>Decode and verify the resource token JWT.</li>
<li>Verify <tt>iss</tt> matches the resource the agent sent the request to.</li>
<li>Verify <tt>agent</tt> matches the agent's own identifier.</li>
<li>Verify <tt>agent_jkt</tt> matches the JWK Thumbprint of the agent's signing key.</li>
<li>Verify <tt>exp</tt> is in the future.</li>
<li>Send the resource token to the agent's PS's token endpoint.</li>
</ol>
</section>
</section>
</section>

<section anchor="person-server"><name>Person Server</name>
<t>This section defines how agents obtain authorization from their person server. When accessing a remote resource, the agent sends a resource token to the PS's token endpoint. When performing local actions not governed by a remote resource, the agent requests permission from the PS's permission endpoint. In both cases, the PS evaluates the request against mission scope, handles user consent if needed, and uses the same requirement response patterns.</t>

<section anchor="ps-token-endpoint"><name>PS Token Endpoint</name>
<t>The PS's <tt>token_endpoint</tt> is where agents send token requests. The PS evaluates the request, handles user consent if needed, and either issues the auth token directly or federates with the resource's AS.</t>

<section anchor="token-endpoint-modes"><name>Token Endpoint Modes</name>
<table>
<thead>
<tr>
<th>Mode</th>
<th>Key Parameters</th>
<th>Use Case</th>
</tr>
</thead>

<tbody>
<tr>
<td>Direct issuance</td>
<td><tt>resource_token</tt> (<tt>aud</tt> = PS)</td>
<td>PS issues auth token directly (three-party)</td>
</tr>

<tr>
<td>Federated issuance</td>
<td><tt>resource_token</tt> (<tt>aud</tt> = AS)</td>
<td>PS federates with AS for auth token (four-party)</td>
</tr>

<tr>
<td>Call chaining</td>
<td><tt>resource_token</tt> + <tt>upstream_token</tt></td>
<td>Resource acting as agent</td>
</tr>
</tbody>
</table></section>

<section anchor="concurrent-token-requests"><name>Concurrent Token Requests</name>
<t>An agent MAY have multiple token requests pending at the PS simultaneously — for example, when a mission requires access to several resources. Each request has its own pending URL and lifecycle. The PS MUST handle concurrent requests independently. Some requests may be resolved without user interaction (e.g., within existing mission scope), while others may require consent. The PS is responsible for managing concurrent user interactions — for example, by batching consent prompts or serializing them.</t>
</section>

<section anchor="agent-token-request"><name>Agent Token Request</name>
<t>The agent MUST make a signed POST to the PS's <tt>token_endpoint</tt>. The request MUST include an HTTP Sig <xref target="http-message-signatures-profile"/> and the agent MUST present its agent token via the <tt>Signature-Key</tt> header using <tt>scheme=jwt</tt>.</t>
<t><strong>Request parameters:</strong></t>

<ul spacing="compact">
<li><tt>resource_token</tt> (REQUIRED): The resource token.</li>
<li><tt>upstream_token</tt> (OPTIONAL): An auth token from an upstream authorization, used in call chaining <xref target="call-chaining"/>.</li>
<li><tt>justification</tt> (OPTIONAL): A Markdown string declaring why access is being requested. The PS SHOULD present this value to the user during consent. The PS MUST sanitize the Markdown before rendering to users. The PS MAY log the <tt>justification</tt> for audit and monitoring purposes. <strong>TODO:</strong> Define recommended sections.</li>
<li><tt>login_hint</tt> (OPTIONAL): Hint about who to authorize, per <xref target="OpenID.Core"/> Section 3.1.2.1.</li>
<li><tt>tenant</tt> (OPTIONAL): Tenant identifier, per OpenID Connect Enterprise Extensions 1.0 <xref target="OpenID.Enterprise"/>.</li>
<li><tt>domain_hint</tt> (OPTIONAL): Domain hint, per OpenID Connect Enterprise Extensions 1.0 <xref target="OpenID.Enterprise"/>.</li>
</ul>
<t><strong>Example request:</strong></t>

<sourcecode type="http"><![CDATA[POST /token HTTP/1.1
Host: ps.example
Content-Type: application/json
Prefer: wait=45
Signature-Input: sig=("@method" "@authority"
    "@path" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "resource_token": "eyJhbGc...",
  "justification": "Find available meeting times"
}
]]>
</sourcecode>
</section>

<section anchor="ps-response"><name>PS Response</name>
<t>When the resource token's <tt>aud</tt> matches the PS's own identifier (three-party), the PS evaluates the request and issues the auth token directly — no AS federation is needed. When <tt>aud</tt> identifies a different server (four-party), the PS federates with the AS per <xref target="ps-as-federation"/>.</t>
<t>In both cases, the PS handles user consent if needed and returns one of:</t>
<t><strong>Direct grant response</strong> (<tt>200</tt>):</t>

<sourcecode type="json"><![CDATA[{
  "auth_token": "eyJhbGc...",
  "expires_in": 3600
}
]]>
</sourcecode>
<t><strong>User interaction required response</strong> (<tt>202</tt>):</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 202 Accepted
Location: /pending/abc123
Retry-After: 0
Cache-Control: no-store
AAuth-Requirement: requirement=interaction;
    url="https://ps.example/interaction"; code="ABCD1234"
Content-Type: application/json

{
  "status": "pending"
}
]]>
</sourcecode>
<t>In four-party mode, the PS may also pass through a clarification from the AS to the agent via the <tt>202</tt> response <xref target="as-token-endpoint"/>.</t>
</section>
</section>

<section anchor="user-interaction"><name>User Interaction</name>
<t>When a server responds with <tt>202</tt> and <tt>AAuth-Requirement: requirement=interaction</tt>, the <tt>url</tt> and <tt>code</tt> parameters in the header tell the agent where to send the user <xref target="requirement-responses"/>. The agent constructs the user-facing URL as <tt>{url}?code={code}</tt> and directs the user using one of the methods defined in <xref target="requirement-responses"/> (browser redirect, QR code, or display code).</t>
<t>When the agent has a browser, it MAY append a <tt>callback</tt> parameter:</t>

<artwork><![CDATA[{url}?code={code}&callback={callback_url}
]]>
</artwork>
<t>The <tt>callback</tt> URL is constructed from the agent's <tt>callback_endpoint</tt> metadata. When present, the server redirects the user's browser to the <tt>callback</tt> URL after the user completes the action. If no <tt>callback</tt> parameter is provided, the server displays a completion page and the agent relies on polling to detect completion.</t>
<t>The <tt>code</tt> parameter is single-use: once the user arrives at the URL with a valid code, the code is consumed and cannot be reused.</t>
</section>

<section anchor="clarification-chat"><name>Clarification Chat</name>
<t>During user consent, the user may ask questions about the agent's stated justification. The PS delivers these questions to the agent, and the agent responds. This enables a consent dialog without requiring the agent to have a direct channel to the user.</t>
<t>Agents that support clarification chat declare this via the <tt>AAuth-Capabilities</tt> request header <xref target="aauth-capabilities"/> by including the <tt>clarification</tt> capability value.</t>

<section anchor="requirement-clarification"><name>Clarification Required</name>
<t>A server MUST use <tt>requirement=clarification</tt> with a <tt>202 Accepted</tt> response when it needs the recipient to answer a question before proceeding. The response body MUST include a <tt>clarification</tt> field containing the question and MAY include <tt>timeout</tt> and <tt>options</tt> fields.</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 202 Accepted
Location: /pending/abc123
Retry-After: 0
Cache-Control: no-store
AAuth-Requirement: requirement=clarification
Content-Type: application/json

{
  "status": "pending",
  "clarification": "Why do you need write access to my calendar?",
  "timeout": 120
}
]]>
</sourcecode>
<t>Body fields:</t>

<ul spacing="compact">
<li><tt>clarification</tt> (REQUIRED): A Markdown string containing the question.</li>
<li><tt>timeout</tt> (OPTIONAL): Seconds until the server times out the request. The recipient MUST respond before this deadline.</li>
<li><tt>options</tt> (OPTIONAL): An array of string values when the question has discrete choices.</li>
</ul>
<t>The recipient MUST respond with one of the actions defined in <xref target="agent-response-to-clarification"/>: a clarification response, an updated request, or a cancellation. This requirement is used by both PSes (delivering user questions to agents) and ASes (requesting clarification from PSes).</t>
</section>

<section anchor="clarification-flow"><name>Clarification Flow</name>
<t>When the user asks a question during consent, the PS returns a <tt>202</tt> with <tt>AAuth-Requirement: requirement=clarification</tt>.</t>
</section>

<section anchor="agent-response-to-clarification"><name>Agent Response to Clarification</name>
<t>The agent MUST respond to a clarification with one of:</t>

<ol spacing="compact">
<li><strong>Clarification response</strong>: POST a <tt>clarification_response</tt> to the pending URL.</li>
<li><strong>Updated request</strong>: POST a new <tt>resource_token</tt> to the pending URL, replacing the original request with updated scope or parameters.</li>
<li><strong>Cancel request</strong>: DELETE the pending URL to withdraw the request.</li>
</ol>

<section anchor="clarification-response"><name>Clarification Response</name>
<t>The agent responds by POSTing JSON with <tt>clarification_response</tt> to the pending URL:</t>

<sourcecode type="http"><![CDATA[POST /pending/abc123 HTTP/1.1
Host: ps.example
Content-Type: application/json
Signature-Input: sig=("@method" "@authority"
    "@path" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "clarification_response":
    "I need to create a meeting invite
     for the participants you listed."
}
]]>
</sourcecode>
<t>The <tt>clarification_response</tt> value is a Markdown string. <strong>TODO:</strong> Define recommended sections. After posting, the agent resumes polling with <tt>GET</tt>.</t>
</section>

<section anchor="updated-request"><name>Updated Request</name>
<t>The agent MAY obtain a new resource token from the resource (e.g., with reduced scope) and POST it to the pending URL:</t>

<sourcecode type="http"><![CDATA[POST /pending/abc123 HTTP/1.1
Host: ps.example
Content-Type: application/json
Signature-Input: sig=("@method" "@authority"
    "@path" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "resource_token": "eyJ...",
  "justification": "I've reduced my request to read-only access."
}
]]>
</sourcecode>
<t>The new resource token MUST have the same <tt>iss</tt>, <tt>agent</tt>, and <tt>agent_jkt</tt> as the original. The PS presents the updated request to the user. A <tt>justification</tt> is OPTIONAL but RECOMMENDED to explain the change to the user.</t>
</section>

<section anchor="cancel-request"><name>Cancel Request</name>
<t>The agent MAY cancel the request by sending DELETE to the pending URL:</t>

<sourcecode type="http"><![CDATA[DELETE /pending/abc123 HTTP/1.1
Host: ps.example
Signature-Input: sig=("@method" "@authority"
    "@path" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."
]]>
</sourcecode>
<t>The PS terminates the consent session and informs the user that the agent withdrew its request. Subsequent requests to the pending URL return <tt>410 Gone</tt>.</t>
</section>
</section>

<section anchor="clarification-limits"><name>Clarification Limits</name>
<t>PSes SHOULD enforce limits on clarification rounds (recommended: 5 rounds maximum). Clarification responses from agents are untrusted input and MUST be sanitized before display to the user.</t>
</section>
</section>

<section anchor="permission-endpoint"><name>Permission Endpoint</name>
<t>The permission endpoint enables agents to request permission from the PS for actions not governed by a remote resource — for example, executing tool calls, writing files, or sending messages on behalf of the user. This enables governance before any resources support AAuth. The permission endpoint MAY be used with or without a mission.</t>
<t>When a mission is active, the mission approval MAY include a list of pre-approved tools in the <tt>approved_tools</tt> field. The agent calls the permission endpoint only for actions not covered by pre-approved tools.</t>

<section anchor="permission-request"><name>Permission Request</name>
<t>The agent MUST make a signed POST to the PS's <tt>permission_endpoint</tt>. The request MUST include an HTTP Sig <xref target="http-message-signatures-profile"/> and the agent MUST present its agent token via the <tt>Signature-Key</tt> header.</t>
<t><strong>Request parameters:</strong></t>

<ul spacing="compact">
<li><tt>action</tt> (REQUIRED): A string identifying the action the agent wants to perform (e.g., a tool name).</li>
<li><tt>description</tt> (OPTIONAL): A Markdown string describing what the action will do and why.</li>
<li><tt>parameters</tt> (OPTIONAL): A JSON object containing the parameters the agent intends to pass to the action.</li>
<li><tt>mission</tt> (OPTIONAL): Mission object with <tt>approver</tt> and <tt>s256</tt> fields, binding the request to a mission. When present, the PS evaluates the request against the mission context and log history.</li>
</ul>

<sourcecode type="http"><![CDATA[POST /permission HTTP/1.1
Host: ps.example
Content-Type: application/json
Signature-Input: sig=("@method" "@authority" "@path" \
    "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "action": "SendEmail",
  "description": "Send the proposed itinerary to the user",
  "parameters": {
    "to": "user@example.com",
    "subject": "Japan trip itinerary"
  },
  "mission": {
    "approver": "https://ps.example",
    "s256": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
  }
}
]]>
</sourcecode>
</section>

<section anchor="permission-response"><name>Permission Response</name>
<t>If the PS can decide immediately, it returns <tt>200 OK</tt>:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 200 OK
Content-Type: application/json

{
  "permission": "granted"
}
]]>
</sourcecode>
<t>The <tt>permission</tt> field is one of:</t>

<ul spacing="compact">
<li><tt>granted</tt>: The agent MAY proceed with the action.</li>
<li><tt>denied</tt>: The agent MUST NOT proceed. The response MAY include a <tt>reason</tt> field with a Markdown string explaining why.</li>
</ul>
<t>If the mission is no longer active, the PS returns a mission status error <xref target="mission-status-errors"/>.</t>
<t>If the PS requires user input, it returns a deferred response <xref target="deferred-responses"/> using the same pattern as other AAuth endpoints. The agent polls until the PS returns a final response.</t>
<t>The PS SHOULD record all permission requests and responses. When a mission is present, the PS records the permission request and response in the mission log.</t>
</section>
</section>

<section anchor="audit-endpoint"><name>Audit Endpoint</name>
<t>The audit endpoint enables agents to log actions they have performed, providing the PS with a record for governance and monitoring. The agent sends a signed POST to the PS's <tt>audit_endpoint</tt> after performing an action. The audit endpoint requires a mission — there is no audit outside a mission context.</t>

<section anchor="audit-request"><name>Audit Request</name>
<t>The agent MUST make a signed POST to the PS's <tt>audit_endpoint</tt>. The request MUST include an HTTP Sig <xref target="http-message-signatures-profile"/> and the agent MUST present its agent token via the <tt>Signature-Key</tt> header.</t>
<t><strong>Request parameters:</strong></t>

<ul spacing="compact">
<li><tt>mission</tt> (REQUIRED): Mission object with <tt>approver</tt> and <tt>s256</tt> fields.</li>
<li><tt>action</tt> (REQUIRED): A string identifying the action that was performed.</li>
<li><tt>description</tt> (OPTIONAL): A Markdown string describing what was done and the outcome.</li>
<li><tt>parameters</tt> (OPTIONAL): A JSON object containing the parameters that were used.</li>
<li><tt>result</tt> (OPTIONAL): A JSON object containing the result or outcome of the action.</li>
</ul>

<sourcecode type="http"><![CDATA[POST /audit HTTP/1.1
Host: ps.example
Content-Type: application/json
Signature-Input: sig=("@method" "@authority" "@path" \
    "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "mission": {
    "approver": "https://ps.example",
    "s256": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
  },
  "action": "WebSearch",
  "description": "Searched for flights to Tokyo in May",
  "parameters": {
    "query": "flights to Tokyo May 2026"
  },
  "result": {
    "status": "completed",
    "summary": "Found 12 flight options"
  }
}
]]>
</sourcecode>
</section>

<section anchor="audit-response"><name>Audit Response</name>
<t>The PS returns <tt>201 Created</tt> to acknowledge the record:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 201 Created
]]>
</sourcecode>
<t>The audit endpoint is fire-and-forget — the agent SHOULD NOT block on the response. The PS records the audit entry in the mission log. The PS MAY use audit records to detect anomalous behavior, alert the user, or revoke the mission.</t>
<t>If the mission is no longer active, the PS returns a mission status error <xref target="mission-status-errors"/>.</t>
</section>
</section>

<section anchor="interaction-endpoint"><name>Interaction Endpoint</name>
<t>The interaction endpoint enables the agent to reach the user through the PS. The agent uses this endpoint to forward interaction requirements from resources that it cannot handle directly, to ask the user questions, to relay payment approvals, or to propose mission completion. The <tt>interaction_endpoint</tt> URL is published in the PS's well-known metadata <xref target="ps-metadata"/>. The interaction endpoint MAY be used with or without a mission.</t>

<section anchor="interaction-request"><name>Interaction Request</name>
<t>The agent MUST make a signed POST to the PS's <tt>interaction_endpoint</tt>. The request MUST include an HTTP Sig <xref target="http-message-signatures-profile"/> and the agent MUST present its agent token via the <tt>Signature-Key</tt> header.</t>
<t><strong>Request parameters:</strong></t>

<ul spacing="compact">
<li><tt>type</tt> (REQUIRED): The type of interaction. One of <tt>interaction</tt>, <tt>payment</tt>, <tt>question</tt>, or <tt>completion</tt>.</li>
<li><tt>description</tt> (OPTIONAL): A Markdown string providing context for the user.</li>
<li><tt>url</tt> (OPTIONAL): The interaction URL to relay to the user (for <tt>interaction</tt> and <tt>payment</tt> types).</li>
<li><tt>code</tt> (OPTIONAL): The interaction code associated with the URL.</li>
<li><tt>question</tt> (OPTIONAL): A Markdown string containing a question for the user (for <tt>question</tt> type).</li>
<li><tt>summary</tt> (OPTIONAL): A Markdown string summarizing what the agent accomplished (for <tt>completion</tt> type).</li>
<li><tt>mission</tt> (OPTIONAL): Mission object with <tt>approver</tt> and <tt>s256</tt> fields, binding the request to a mission.</li>
</ul>
<t><strong>Relay interaction example:</strong></t>

<sourcecode type="http"><![CDATA[POST /interaction HTTP/1.1
Host: ps.example
Content-Type: application/json
Signature-Input: sig=("@method" "@authority" "@path" \
    "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "type": "interaction",
  "description": "The booking service needs you to confirm payment",
  "url": "https://booking.example/confirm",
  "code": "X7K2-M9P4",
  "mission": {
    "approver": "https://ps.example",
    "s256": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
  }
}
]]>
</sourcecode>
<t><strong>Completion example:</strong></t>

<sourcecode type="http"><![CDATA[POST /interaction HTTP/1.1
Host: ps.example
Content-Type: application/json
Signature-Input: sig=("@method" "@authority" "@path" \
    "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "type": "completion",
  "summary": "# Japan Trip Booked\n\n
    Booked round-trip flights on ANA and
    10 nights across three cities.
    Total cost: $4,850.
    Itinerary sent to your email.",
  "mission": {
    "approver": "https://ps.example",
    "s256": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
  }
}
]]>
</sourcecode>
</section>

<section anchor="interaction-response"><name>Interaction Response</name>
<t>For <tt>interaction</tt> and <tt>payment</tt> types, the PS relays the interaction to the user and returns a deferred response <xref target="deferred-responses"/>. The agent polls until the user completes the interaction.</t>
<t>For <tt>question</tt> type, the PS delivers the question to the user and returns the answer:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 200 OK
Content-Type: application/json

{
  "answer": "Yes, go ahead with the refundable option."
}
]]>
</sourcecode>
<t>For <tt>completion</tt> type, the PS presents the summary to the user. The user either accepts — the PS terminates the mission and returns <tt>200 OK</tt> — or responds with follow-up questions via clarification <xref target="clarification-chat"/>, keeping the mission active. The PS returns a deferred response while the user reviews.</t>
<t>If the PS cannot reach the user and the agent does not have the <tt>interaction</tt> capability, the PS returns <tt>interaction_required</tt>. If the mission is no longer active, the PS returns a mission status error <xref target="mission-status-errors"/>. The PS SHOULD record all interaction requests and responses. When a mission is active, the PS records the interaction in the mission log.</t>
</section>
</section>

<section anchor="re-authorization"><name>Re-authorization</name>
<t>AAuth does not have a separate refresh token or refresh flow. When an auth token expires, the agent obtains a fresh resource token from the resource's authorization endpoint and submits it to the PS's token endpoint — the same flow as the initial authorization. This gives the resource a voice in every re-authorization: the resource can adjust scope, require step-up authorization, or deny access based on current policy.</t>
<t>When an agent rotates its signing key, all existing auth tokens are bound to the old key and can no longer be used. The agent MUST re-authorize by obtaining fresh resource tokens and submitting them to the PS.</t>
<t>Agents SHOULD proactively obtain a new agent token and refresh all auth tokens before the current agent token expires, to avoid service interruptions. Auth tokens MUST NOT have an <tt>exp</tt> value that exceeds the <tt>exp</tt> of the agent token used to obtain them — a resource MUST reject an auth token whose associated agent token has expired.</t>
</section>
</section>

<section anchor="missions"><name>Mission</name>
<t>Missions are OPTIONAL. The protocol operates in all modes without missions. When used, missions provide scoped authorization contexts that guide an agent's work across multiple resource accesses — enabling scope pre-approval, reduced consent fatigue, and centralized audit. A mission is a natural-language description of what the agent intends to accomplish, proposed by the agent and approved by the PS. The PS uses the mission to evaluate every subsequent request in context — it is the only party with the mission content, the user relationship, and the full history of the agent's actions. Once approved, the mission's <tt>s256</tt> identifier is included in subsequent resource interactions via the <tt>AAuth-Mission</tt> header.</t>

<section anchor="mission-creation-1"><name>Mission Creation</name>
<t>The agent creates a mission by sending a proposal to the PS's <tt>mission_endpoint</tt>. The agent MUST make a signed POST with an HTTP Sig <xref target="http-message-signatures-profile"/>, presenting its agent token via the <tt>Signature-Key</tt> header using <tt>scheme=jwt</tt>.</t>
<t>The proposal includes a Markdown description of what the agent intends to accomplish, and MAY include a list of tools the agent wants to use:</t>

<sourcecode type="json"><![CDATA[{
  "description": "# Plan Japan Vacation\n\n
    Plan and book a trip to Japan next month
    for 2 adults. Budget around $5k.
    Propose an itinerary before booking.",
  "tools": [
    {
      "name": "WebSearch",
      "description": "Search the web"
    },
    {
      "name": "BookFlight",
      "description": "Book flights"
    },
    {
      "name": "BookHotel",
      "description": "Book hotels"
    }
  ]
}
]]>
</sourcecode>
<t>The PS MAY return a <tt>202 Accepted</tt> deferred response <xref target="deferred-responses"/> if human review, clarification, or approval is needed. During this phase, the PS and user may engage in clarification chat <xref target="clarification-chat"/> with the agent to refine the mission scope, ask questions about the agent's intent, or negotiate which tools are needed. The PS or user may also modify the description — the approved mission MAY differ from the original proposal.</t>
</section>

<section anchor="mission-approval"><name>Mission Approval</name>
<t>When the PS approves the mission, the response body is a JSON object — the <strong>mission blob</strong> — containing the approved mission and session-specific information. The PS returns the <tt>AAuth-Mission</tt> header with the <tt>approver</tt> and <tt>s256</tt> values:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 200 OK
Content-Type: application/json
AAuth-Mission: approver="https://ps.example";
    s256="dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"

{
  "approver": "https://ps.example",
  "agent": "aauth:assistant@agent.example",
  "approved_at": "2026-04-07T14:30:00Z",
  "description": "# Plan Japan Vacation\n\n
    Plan and book a trip to Japan next month
    for 2 adults. Budget around $5k.
    Propose an itinerary before booking.",
  "approved_tools": [
    {
      "name": "WebSearch",
      "description": "Search the web"
    },
    {
      "name": "Read",
      "description": "Read files and web pages"
    }
  ],
  "capabilities": [
    "interaction",
    "payment"
  ]
}
]]>
</sourcecode>
<t>The mission blob MUST include:</t>

<ul spacing="compact">
<li><tt>approver</tt>: HTTPS URL of the entity that approved the mission. Currently this is always the PS.</li>
<li><tt>agent</tt>: The agent identifier (<tt>aauth:local@domain</tt>).</li>
<li><tt>approved_at</tt>: ISO 8601 timestamp of when the mission was approved. Ensures the <tt>s256</tt> is globally unique.</li>
<li><tt>description</tt>: Markdown string describing the approved mission scope.</li>
</ul>
<t>The mission blob MAY include:</t>

<ul spacing="compact">
<li><tt>approved_tools</tt>: Array of tool objects (each with <tt>name</tt> and <tt>description</tt>) that the agent may use without per-call permission at the PS's permission endpoint <xref target="permission-endpoint"/>.</li>
<li><tt>capabilities</tt>: Array of capability strings (e.g., <tt>interaction</tt>, <tt>payment</tt>) that the PS can provide on behalf of the user for this session. The PS determines these based on whether it can reach the specific user — for example, via push notification, email, or an active session. The agent unions these with its own capabilities when constructing the <tt>AAuth-Capabilities</tt> request header <xref target="aauth-capabilities"/>.</li>
</ul>
<t>The <tt>s256</tt> in the <tt>AAuth-Mission</tt> header is the base64url-encoded SHA-256 hash of the response body bytes. The agent verifies the hash by computing SHA-256 over the exact response body bytes. The agent MUST store the mission body bytes exactly as received — no re-serialization.</t>
<t>The approved description MAY differ from the proposal — the PS or user may refine, constrain, or expand the mission during review. The approved tools MAY be a subset of the proposed tools. The agent MUST use the <tt>approver</tt> and <tt>s256</tt> from the <tt>AAuth-Mission</tt> header in all subsequent <tt>AAuth-Mission</tt> request headers.</t>
</section>

<section anchor="mission-log"><name>Mission Log</name>
<t>The approved mission description is immutable — the <tt>s256</tt> hash binds it permanently. Missions do not change; they accumulate context.</t>
<t>All agent interactions with the PS within a mission context form the <strong>mission log</strong>: token requests (with justifications), permission requests and responses, audit records, interaction requests, and clarification chats. The PS maintains this log as an ordered record of the agent's actions and the governance decisions made. The mission log gives the PS the full history it needs to evaluate whether each new request is consistent with the mission's intent.</t>
<t>The agent includes the mission context in all resource interactions via the <tt>AAuth-Mission</tt> header. When the agent sends a resource token to its PS, the PS evaluates the request against the mission context and log history before federating with the resource's AS.</t>
</section>

<section anchor="mission-completion-1"><name>Mission Completion</name>
<t>When the agent believes the mission is complete, it sends a <tt>completion</tt> interaction to the PS's interaction endpoint <xref target="interaction-endpoint"/> with a summary of what was accomplished. The PS presents the summary to the user. The user either accepts — the PS terminates the mission — or responds with follow-up questions via clarification, keeping the mission active. This is the most common mission lifecycle path.</t>
</section>

<section anchor="mission-management"><name>Mission Management</name>
<t>A mission has one of two states:</t>

<ul spacing="compact">
<li><strong>active</strong>: The mission is in progress. The agent can make requests against it.</li>
<li><strong>terminated</strong>: The mission is permanently ended. The PS MUST reject requests with <tt>mission_terminated</tt>.</li>
</ul>
<t>The mechanisms for state transitions beyond completion — revocation, delegation tree queries, and administrative interfaces — will be defined in a companion specification.</t>
</section>

<section anchor="mission-status-errors"><name>Mission Status Errors</name>
<t>When an agent makes a request to any PS endpoint with a <tt>mission</tt> parameter referencing a mission that is no longer active, the PS MUST return an error:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 403 Forbidden
Content-Type: application/json

{
  "error": "mission_terminated",
  "mission_status": "terminated"
}
]]>
</sourcecode>
<table>
<thead>
<tr>
<th>Error</th>
<th>Mission Status</th>
<th>Meaning</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>mission_terminated</tt></td>
<td><tt>terminated</tt></td>
<td>The mission is permanently ended. The agent MUST stop acting on this mission.</td>
</tr>
</tbody>
</table></section>

<section anchor="aauth-mission-request-header"><name>AAuth-Mission Request Header</name>
<t>The <tt>AAuth-Mission</tt> header is a request header sent by the agent on initial requests to a resource when operating in a mission context. It signals to the resource that the agent has a person server and is operating within a mission.</t>

<sourcecode type="http"><![CDATA[AAuth-Mission:
    approver="https://ps.example";
    s256="dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
]]>
</sourcecode>
<t>Parameters:</t>

<ul spacing="compact">
<li><tt>approver</tt>: The HTTPS URL of the entity that approved the mission</li>
<li><tt>s256</tt>: The base64url-encoded SHA-256 hash of the approved mission JSON</li>
</ul>
<t>When a mission-aware resource receives a request with the <tt>AAuth-Mission</tt> header, it includes the mission object (<tt>approver</tt> and <tt>s256</tt>) in the resource token it issues. When a resource does not support missions, it ignores the header.</t>
<t>Agents operating in a mission context MUST include the <tt>AAuth-Mission</tt> header on requests to resources that do not include an auth token containing a <tt>mission</tt> claim.</t>
</section>
</section>

<section anchor="access-server-federation"><name>Access Server Federation</name>
<t>This section defines auth tokens and the mechanisms by which they are issued. The auth token is the end result of the authorization flow — a JWT issued by an access server that grants an agent access to a specific resource. This section covers the AS token endpoint, PS-AS federation, and the auth token structure.</t>

<section anchor="as-token-endpoint"><name>AS Token Endpoint</name>
<t>The AS evaluates resource policy and issues auth tokens. It accepts JSON POST requests.</t>

<section anchor="ps-to-as-token-request"><name>PS-to-AS Token Request</name>
<t>The PS MUST make a signed POST to the AS's <tt>token_endpoint</tt>. The PS authenticates via an HTTP Sig <xref target="http-message-signatures-profile"/>.</t>
<t><strong>Request parameters:</strong></t>

<ul spacing="compact">
<li><tt>resource_token</tt> (REQUIRED): The resource token issued by the resource.</li>
<li><tt>agent_token</tt> (REQUIRED): The agent's agent token.</li>
<li><tt>upstream_token</tt> (OPTIONAL): An auth token from an upstream authorization, used in call chaining <xref target="call-chaining"/>.</li>
</ul>
<t><strong>Example request:</strong></t>

<sourcecode type="http"><![CDATA[POST /token HTTP/1.1
Host: as.resource.example
Content-Type: application/json
Signature-Input: sig=("@method" "@authority"
    "@path" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwks_uri;
    jwks_uri="https://ps.example/.well-known/jwks.json"

{
  "resource_token": "eyJhbGc...",
  "agent_token": "eyJhbGc..."
}
]]>
</sourcecode>
</section>

<section anchor="as-response"><name>AS Response</name>
<t>The PS calls the AS token endpoint and follows the standard deferred response loop <xref target="deferred-responses"/>: it handles <tt>202</tt> and <tt>402</tt> responses and continues until it receives a <tt>200</tt> with an auth token or a terminal error.</t>
<t><strong>Direct grant response</strong> (<tt>200</tt>):</t>

<sourcecode type="json"><![CDATA[{
  "auth_token": "eyJhbGc...",
  "expires_in": 3600
}
]]>
</sourcecode>
<t>The AS MAY return <tt>202 Accepted</tt> with an <tt>AAuth-Requirement</tt> header indicating what is needed before it can issue an auth token:</t>

<ul spacing="compact">
<li><strong><tt>requirement=claims</tt></strong> <xref target="requirement-claims"/>: The AS needs identity claims. The body includes <tt>required_claims</tt>. The PS MUST provide the requested claims (including a directed <tt>sub</tt> identifier for the resource) by POSTing to the <tt>Location</tt> URL. The AS cannot know what claims it needs until it has processed the resource token.</li>
<li><strong><tt>requirement=clarification</tt></strong> <xref target="requirement-clarification"/>: The AS needs a question answered. The PS triages who answers: itself (if mission context has the answer), the user, or the agent. The PS MAY pass the clarification down to the agent via a <tt>202</tt> response.</li>
<li><strong><tt>requirement=interaction</tt></strong> <xref target="requirement-responses"/>: The AS requires user interaction — for example, the user must authenticate at the AS to bind their PS, or the resource owner must approve access. The PS directs the user to the AS's interaction URL, or passes the interaction requirement back to the agent.</li>
<li><strong><tt>requirement=approval</tt></strong> <xref target="requirement-responses"/>: The AS is obtaining approval without requiring user direction.</li>
</ul>
<t><strong>Payment required</strong> (<tt>402</tt>):</t>
<t>The AS MAY return <tt>402 Payment Required</tt> when a billing relationship is required before it will issue auth tokens. The <tt>402</tt> response includes payment details per an applicable payment protocol such as x402 <xref target="x402"/> or the Machine Payment Protocol (MPP) (<xref target="I-D.ryan-httpauth-payment"/>). The response MUST include a <tt>Location</tt> header for the PS to poll after payment is settled.</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 402 Payment Required
Location: https://as.resource.example/token/pending/xyz
WWW-Authenticate: Payment id="x7Tg2pLq", method="stripe",
    request="eyJhbW91bnQiOiIxMDAw..."
]]>
</sourcecode>
<t>The PS settles payment per the indicated protocol and polls the <tt>Location</tt> URL. When payment is confirmed, the AS continues processing the token request — which may result in a <tt>200</tt> with an auth token, or a further <tt>202</tt> requiring claims, interaction, or approval.</t>
<t>The PS caches the billing relationship per AS. Future token requests from the same PS to the same AS skip the billing step. The payment protocol, settlement mechanism, and billing terms are out of scope for this specification.</t>
</section>

<section anchor="auth-token-delivery"><name>Auth Token Delivery</name>
<t>When the AS issues an auth token (<tt>200</tt> response), the PS MUST verify the auth token before returning it to the agent:</t>

<ol spacing="compact">
<li>Verify the auth token JWT signature using the AS's JWKS <xref target="jwks-discovery"/>.</li>
<li>Verify <tt>iss</tt> matches the AS the PS sent the token request to.</li>
<li>Verify <tt>aud</tt> matches the resource identified by the resource token's <tt>iss</tt>.</li>
<li>Verify <tt>agent</tt> matches the agent that submitted the token request.</li>
<li>Verify <tt>cnf.jwk</tt> matches the agent's signing key.</li>
<li>Verify <tt>act</tt> is present and accurately reflects the delegation chain — <tt>act.sub</tt> identifies the requesting agent, and any nested <tt>act</tt> claims match the upstream delegation context.</li>
<li>Verify <tt>scope</tt> is consistent with what was requested — not broader than the scope in the resource token.</li>
</ol>
<t>After verification, the PS returns the auth token to the agent. The agent presents the auth token to the resource via the <tt>Signature-Key</tt> header <xref target="auth-token-usage"/>. The resource verifies the auth token against the AS's JWKS <xref target="auth-token-verification"/>.</t>
<t>The agent receives the auth token from its trusted PS, so signature verification is not strictly required. However, agents SHOULD verify the auth token's signature to detect errors early. Agents MUST verify that <tt>aud</tt>, <tt>cnf</tt>, <tt>agent</tt>, and <tt>act</tt> match their own values.</t>
</section>
</section>

<section anchor="requirement-claims"><name>Claims Required</name>
<t>A server MUST use <tt>requirement=claims</tt> with a <tt>202 Accepted</tt> response when it needs identity claims to process a request. The response body MUST include a <tt>required_claims</tt> field containing an array of claim names.</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 202 Accepted
Location: https://as.resource.example/token/pending/xyz
Retry-After: 0
Cache-Control: no-store
AAuth-Requirement: requirement=claims
Content-Type: application/json

{
  "status": "pending",
  "required_claims": ["email", "org"]
}
]]>
</sourcecode>
<t>The recipient MUST provide the requested claims (including a directed user identifier as <tt>sub</tt>) by POSTing to the <tt>Location</tt> URL. The recipient MUST include an HTTP Sig <xref target="http-message-signatures-profile"/> on the POST. Claims not recognized by the recipient SHOULD be ignored. This requirement is used by ASes to request identity claims from PSes during token issuance.</t>
</section>

<section anchor="ps-as-federation"><name>PS-AS Federation</name>
<t>The PS is the only entity that calls AS token endpoints. When the PS receives a resource token from an agent, the resource token's <tt>aud</tt> claim identifies where to send the token request. If <tt>aud</tt> matches the PS's own identifier, the PS issues the auth token directly (three-party). If <tt>aud</tt> identifies a different server (an AS), the PS discovers the AS's metadata at <tt>{aud}/.well-known/aauth-access.json</tt> <xref target="access-server-metadata"/> and calls the AS's <tt>token_endpoint</tt> <xref target="as-token-endpoint"/> (four-party).</t>

<section anchor="ps-as-trust-establishment"><name>PS-AS Trust Establishment</name>
<t>Trust between the PS and AS is not a separate registration step — it emerges from the AS's response to the PS's first token request. The AS evaluates the token request and responds based on its current policy:</t>

<ul spacing="compact">
<li><strong>Pre-established</strong>: A business relationship configured between the PS and AS, potentially including payment terms, SLA, and compliance requirements. The AS recognizes the PS and processes the token request directly.</li>
<li><strong>Interaction</strong>: The AS returns <tt>202</tt> with <tt>requirement=interaction</tt>, directing the user to authenticate at the AS and confirm their PS. After this one-time binding, the AS trusts future requests from that PS for that user. This is the primary mechanism for establishing trust dynamically.</li>
<li><strong>Payment</strong>: The AS returns <tt>402</tt>, requiring the PS to establish a billing relationship before tokens will be issued. The PS settles payment per the indicated protocol and polls for completion. After billing is established, the AS trusts future requests from that PS.</li>
<li><strong>Claims only</strong>: The AS may trust any PS that can provide sufficient identity claims for a policy decision, without requiring a prior relationship.</li>
</ul>
<t>These mechanisms may compose: for example, the AS may first require payment (<tt>402</tt>), then interaction for user binding (<tt>202</tt>), then claims (<tt>202</tt>) before issuing an auth token. Each step uses the same <tt>Location</tt> URL for polling.</t>

<sourcecode type="ascii-art"><![CDATA[PS                        User                    AS
  |                         |                       |
  |  POST /token            |                       |
  |  resource_token,        |                       |
  |  agent_token            |                       |
  |------------------------------------------------>|
  |                         |                       |
  |  402 Payment Required   |                       |
  |  Location: /token/pending/xyz                   |
  |<------------------------------------------------|
  |                         |                       |
  |  [PS settles payment per indicated protocol]    |
  |                         |                       |
  |  GET /token/pending/xyz |                       |
  |------------------------------------------------>|
  |                         |                       |
  |  202 Accepted           |                       |
  |  requirement=interaction|                       |
  |  url=".../authorize/abc"|                       |
  |<------------------------------------------------|
  |                         |                       |
  |  direct user to URL     |                       |
  |------------------------>|                       |
  |                         |  authenticate, bind PS|
  |                         |---------------------->|
  |                         |                       |
  |  GET /token/pending/xyz |                       |
  |------------------------------------------------>|
  |                         |                       |
  |  202 Accepted           |                       |
  |  requirement=claims     |                       |
  |<------------------------------------------------|
  |                         |                       |
  |  POST /token/pending/xyz|                       |
  |  {sub, email, org}      |                       |
  |------------------------------------------------>|
  |                         |                       |
  |  200 OK (auth_token)    |                       |
  |<------------------------------------------------|
  |                         |                       |
]]>
</sourcecode>
<t>{: #fig-mm-as-trust title="PS-AS Trust Establishment (all steps shown — most requests skip some)"}</t>
</section>

<section anchor="as-decision-logic"><name>AS Decision Logic (Non-Normative)</name>
<t>The following is a non-normative description of how an AS might evaluate a token request:</t>

<ol spacing="compact">
<li><strong>PS = AS (same entity)</strong>: Grant directly. When an organization controls both the PS and AS, the federation call is internal and trust is implicit.</li>
<li><strong>User has bound this PS at the AS</strong>: Apply the user's configured policy for this PS.</li>
<li><strong>PS is pre-established (enterprise agreement)</strong>: Apply the organization's configured policy.</li>
<li><strong>Resource is open or has a free tier</strong>: Grant with restricted scope or rate limits.</li>
<li><strong>Resource requires billing</strong>: Return <tt>402</tt> with payment details.</li>
<li><strong>Resource requires user binding</strong>: Return <tt>202</tt> with <tt>requirement=interaction</tt>.</li>
<li><strong>AS needs identity claims to decide</strong>: Return <tt>202</tt> with <tt>requirement=claims</tt>.</li>
<li><strong>Insufficient trust for requested scope</strong>: Return <tt>403</tt>.</li>
</ol>
<t>The AS is not required to follow this order. The decision logic is entirely at the AS's discretion based on resource policy.</t>
</section>

<section anchor="organization-visibility"><name>Organization Visibility</name>
<t>Organizations benefit from the trust model: an organization's agents share a single PS, and internal resources may share a single AS. The PS provides centralized audit across all agents and missions. Federation is only incurred at the boundary, when an internal agent accesses an external resource. When an organization controls both the PS and AS, the federation call is internal and trust is implicit — this is the degenerate case of the four-party model collapsing to fewer parties.</t>
</section>
</section>

<section anchor="auth-tokens"><name>Auth Token</name>

<section anchor="auth-token-structure"><name>Auth Token Structure</name>
<t>An auth token is a JWT with <tt>typ: aa-auth+jwt</tt> containing:</t>
<t>Header:
- <tt>alg</tt>: Signing algorithm. EdDSA is RECOMMENDED. Implementations MUST NOT accept <tt>none</tt>.
- <tt>typ</tt>: <tt>aa-auth+jwt</tt>
- <tt>kid</tt>: Key identifier</t>
<t>Required payload claims:
- <tt>iss</tt>: The URL of the server that issued the auth token — an AS (four-party) or a PS (three-party)
- <tt>dwk</tt>: The well-known metadata document name for key discovery (<xref target="I-D.hardt-httpbis-signature-key"/>). <tt>aauth-access.json</tt> when issued by an AS, <tt>aauth-person.json</tt> when issued by a PS.
- <tt>aud</tt>: The URL of the resource the agent is authorized to access.
- <tt>jti</tt>: Unique token identifier for replay detection, audit, and revocation
- <tt>agent</tt>: Agent identifier
- <tt>cnf</tt>: Confirmation claim with <tt>jwk</tt> containing the agent's public key
- <tt>act</tt>: Actor claim (<xref target="RFC8693"/>, Section 4.1) identifying the entity that requested this auth token. In direct authorization, <tt>act.sub</tt> is the agent identifier. In call chaining, <tt>act</tt> nests to record the full delegation chain — each intermediary's identity is preserved as a nested <tt>act</tt> claim within the outer <tt>act</tt>. This enables resources to see the complete chain of delegation and make authorization decisions accordingly.
- <tt>iat</tt>: Issued at timestamp
- <tt>exp</tt>: Expiration timestamp. Auth tokens MUST NOT have a lifetime exceeding 1 hour.</t>
<t>Conditional payload claims (at least one MUST be present):
- <tt>sub</tt>: Directed user identifier. An opaque string that identifies the user. The PS SHOULD provide a pairwise pseudonymous identifier per resource (<tt>aud</tt>), preserving user privacy — different resources see different <tt>sub</tt> values for the same user.
- <tt>scope</tt>: Authorized scopes, as a space-separated string of scope values consistent with <xref target="RFC9068"/> Section 2.2.3</t>
<t>At least one of <tt>sub</tt> or <tt>scope</tt> MUST be present.</t>
<t>Optional payload claims:
- <tt>mission</tt>: Mission object. Present when the auth token was issued in the context of a mission. Contains:
  - <tt>approver</tt>: HTTPS URL of the entity that approved the mission
  - <tt>s256</tt>: SHA-256 hash of the approved mission JSON (base64url)</t>
<t>The auth token MAY include additional claims registered in the IANA JSON Web Token Claims Registry <xref target="RFC7519"/> or defined in OpenID Connect Core 1.0 <xref target="OpenID.Core"/> Section 5.1.</t>
</section>

<section anchor="auth-token-usage"><name>Auth Token Usage</name>
<t>Agents present auth tokens via the <tt>Signature-Key</tt> header (<xref target="I-D.hardt-httpbis-signature-key"/>) using <tt>scheme=jwt</tt>:</t>

<sourcecode type="http"><![CDATA[Signature-Key: sig=jwt;
    jwt="eyJhbGciOiJFZERTQSIsInR5cCI6ImF1dGgr..."
]]>
</sourcecode>
</section>

<section anchor="auth-token-verification"><name>Auth Token Verification</name>
<t>When a resource receives an auth token, verify per <xref target="RFC7515"/> and <xref target="RFC7519"/>:</t>

<ol spacing="compact">
<li>Decode the JWT header. Verify <tt>typ</tt> is <tt>aa-auth+jwt</tt>.</li>
<li>Verify <tt>dwk</tt> is <tt>aauth-access.json</tt> (AS-issued) or <tt>aauth-person.json</tt> (PS-issued). Discover the issuer's JWKS via <tt>{iss}/.well-known/{dwk}</tt> per the HTTP Signature Keys specification (<xref target="I-D.hardt-httpbis-signature-key"/>). Locate the key matching the JWT header <tt>kid</tt> and verify the JWT signature.</li>
<li>Verify <tt>exp</tt> is in the future and <tt>iat</tt> is not in the future.</li>
<li>Verify <tt>iss</tt> is a valid HTTPS URL.</li>
<li>Verify <tt>aud</tt> matches the resource's own identifier.</li>
<li>Verify <tt>agent</tt> matches the agent identifier from the request's signing context.</li>
<li>Verify <tt>cnf.jwk</tt> matches the key used to sign the HTTP request.</li>
<li>Verify <tt>act</tt> is present and <tt>act.sub</tt> matches the agent identifier from the request's signing context.</li>
<li>Verify that at least one of <tt>sub</tt> or <tt>scope</tt> is present.</li>
</ol>
</section>

<section anchor="auth-token-response-verification"><name>Auth Token Response Verification</name>
<t>When an agent receives an auth token:</t>

<ol spacing="compact">
<li>SHOULD verify the auth token JWT signature using the issuer's JWKS (the AS in four-party, or the PS in three-party). The agent trusts its PS, so signature verification is not required but is RECOMMENDED to detect errors early.</li>
<li>Verify <tt>iss</tt> matches the resource token's <tt>aud</tt> claim.</li>
<li>Verify <tt>aud</tt> matches the resource the agent intends to access.</li>
<li>Verify <tt>cnf.jwk</tt> matches the agent's own signing key.</li>
<li>Verify <tt>agent</tt> matches the agent's own identifier.</li>
<li>Verify <tt>act.sub</tt> matches the agent's own identifier.</li>
</ol>
</section>

<section anchor="upstream-token-verification"><name>Upstream Token Verification</name>
<t>When the PS receives an <tt>upstream_token</tt> parameter in a call chaining request:</t>

<ol spacing="compact">
<li>Perform Auth Token Verification <xref target="auth-token-verification"/> on the upstream token.</li>
<li>Verify <tt>iss</tt> is a trusted AS (an AS whose auth token the PS previously brokered).</li>
<li>Verify the <tt>aud</tt> in the upstream token matches the resource that is now acting as an agent (i.e., the upstream token was issued for the intermediary resource).</li>
<li>The PS constructs the <tt>act</tt> claim for the downstream auth token by nesting the upstream token's <tt>act</tt> claim inside a new <tt>act</tt> object identifying the intermediary resource's agent identity. This preserves the complete delegation chain.</li>
<li>The PS evaluates its own policy based on the upstream token's claims and mission context. The resulting downstream authorization is not required to be a subset of the upstream scopes — see <xref target="call-chaining"/>.</li>
</ol>
</section>
</section>
</section>

<section anchor="multi-hop"><name>Multi-Hop Resource Access</name>
<t>This section defines how resources act as agents to access downstream resources on behalf of the original caller. In multi-hop scenarios, a resource that receives an authorized request needs to access another resource to fulfill that request. The resource acts as an agent — it has its own agent identity and signing key — and routes the downstream authorization to obtain an auth token for the downstream resource.</t>

<section anchor="call-chaining"><name>Call Chaining</name>
<t>When a resource needs to access a downstream resource on behalf of the caller, it acts as an agent. The resource determines where to send the downstream token request based on the upstream auth token it received:</t>

<ul>
<li><t><strong>Mission present</strong> (<tt>mission.approver</tt> in the upstream auth token): The resource sends the downstream resource token to the PS identified by <tt>mission.approver</tt>, along with its own agent token and the upstream auth token as the <tt>upstream_token</tt>. The PS has mission context and evaluates the downstream request against the mission scope. This is the governed path — the PS sees the full delegation chain for audit.</t>
</li>
<li><t><strong>No mission, <tt>iss</tt> is a PS</strong> (three-party upstream): The resource sends the downstream resource token to the PS identified by <tt>iss</tt>, along with its own agent token and the <tt>upstream_token</tt>. The PS evaluates the request without mission context.</t>
</li>
<li><t><strong>No mission, <tt>iss</tt> is an AS</strong> (four-party upstream, no governance): The resource sends the downstream resource token to the AS identified by <tt>iss</tt>, along with its own agent token and the <tt>upstream_token</tt>. The AS evaluates the request based on resource policy. No PS is involved — no governance context is available.</t>
</li>
</ul>
<t>The recipient (PS or AS) evaluates the downstream request per <xref target="upstream-token-verification"/>.</t>
<t>Note that downstream authorization is not required to be a subset of the upstream scopes. A downstream resource may have capabilities that are orthogonal to the upstream resource — for example, a flight booking API that calls a payment processor needs the payment processor to charge a card, an operation the user and original agent could never perform directly. The downstream resource's scope is constrained by its own AS policy and the PS's evaluation of the mission context, not by the upstream token's scope. The PS provides the governance constraint — it evaluates each hop independently and can deny requests that fall outside the mission or the user's intent.</t>
<t>Because the resource acts as an agent, it MUST have its own agent identity — it MUST publish agent metadata at <tt>/.well-known/aauth-agent.json</tt> so that downstream resources and ASes can verify its identity.</t>
</section>

<section anchor="interaction-chaining"><name>Interaction Chaining</name>
<t>When the PS or AS requires user interaction for the downstream access, it returns a <tt>202</tt> with <tt>requirement=interaction</tt>. Resource 1 chains the interaction back to the original agent by returning its own <tt>202</tt>.</t>
<t>When a resource acting as an agent receives a <tt>202 Accepted</tt> response with <tt>AAuth-Requirement: requirement=interaction</tt>, and the resource needs to propagate this interaction requirement to its caller, it MUST return a <tt>202 Accepted</tt> response to the original agent with its own <tt>AAuth-Requirement</tt> header containing <tt>requirement=interaction</tt> and its own interaction code. The resource MUST provide its own <tt>Location</tt> URL for the original agent to poll. When the user completes interaction and the resource obtains the downstream auth token, the resource completes the original request and returns the result at its pending URL.</t>
</section>
</section>

<section anchor="third-party-login"><name>Third-Party Login</name>
<t>A third party — such as a PS, enterprise portal, app marketplace, or partner site — can direct a user to an agent's or resource's <tt>login_endpoint</tt> to initiate authentication. The agent or resource creates a resource token and sends it to the PS's token endpoint, obtaining an auth token with user identity.</t>
<t>This enables use cases where the user's journey starts outside the agent or resource — for example, an enterprise portal launching an agent for a specific user, an app marketplace connecting a user to a new service, or a PS dashboard directing a user to an agent.</t>

<section anchor="login-endpoint"><name>Login Endpoint</name>
<t>Agents and resources MAY publish a <tt>login_endpoint</tt> in their metadata. The <tt>login_endpoint</tt> accepts the following query parameters:</t>

<ul spacing="compact">
<li><tt>ps</tt> (REQUIRED): The PS URL to authenticate with. The agent or resource MUST verify this is a valid PS by fetching its metadata at <tt>{ps}/.well-known/aauth-person.json</tt> <xref target="ps-metadata"/>.</li>
<li><tt>login_hint</tt> (OPTIONAL): Hint about who to authorize, per <xref target="OpenID.Core"/> Section 3.1.2.1.</li>
<li><tt>domain_hint</tt> (OPTIONAL): Domain hint, per OpenID Connect Enterprise Extensions 1.0 <xref target="OpenID.Enterprise"/>.</li>
<li><tt>tenant</tt> (OPTIONAL): Tenant identifier, per OpenID Connect Enterprise Extensions 1.0 <xref target="OpenID.Enterprise"/>.</li>
<li><tt>start_path</tt> (OPTIONAL): Path on the agent's or resource's origin where the user should be directed after login completes. The recipient MUST validate that <tt>start_path</tt> is a relative path on its own origin.</li>
</ul>
<t><strong>Example login URL:</strong></t>

<artwork><![CDATA[https://agent.example/login
    ?ps=https://ps.example
    &tenant=corp
    &login_hint=user@corp.example
    &start_path=/projects/tokyo-trip
]]>
</artwork>
</section>

<section anchor="login-flow"><name>Login Flow</name>
<t>Upon receiving a request at its <tt>login_endpoint</tt>, the agent or resource:</t>

<ol spacing="compact">
<li>Validates the <tt>ps</tt> parameter by fetching the PS's metadata.</li>
<li>Creates a resource token with <tt>aud</tt> = PS URL, binding the request to its own identity.</li>
<li>POSTs to the PS's <tt>token_endpoint</tt> with the resource token and any provided <tt>login_hint</tt>, <tt>domain_hint</tt>, or <tt>tenant</tt> parameters.</li>
<li>Proceeds with the standard deferred response flow <xref target="deferred-responses"/> — directing the user to the PS's interaction endpoint with the interaction code.</li>
<li>After obtaining the auth token, redirects the user to <tt>start_path</tt> if provided, or to a default landing page.</li>
</ol>
<t>If the user is already authenticated at the PS, the interaction step resolves near-instantly — the PS recognizes the user from its own session. If not, the user completes a normal authentication and consent flow.</t>
<figure anchor="fig-third-party-login"><name>Third-Party Login Flow </name>
<sourcecode type="ascii-art"><![CDATA[User         Third Party     Agent/Resource                  PS
  |               |               |                           |
  |  select       |               |                           |
  |-------------->|               |                           |
  |               |               |                           |
  |  redirect to login_endpoint   |                           |
  |  (ps, tenant, start_path)     |                           |
  |<--------------|               |                           |
  |               |               |                           |
  |  login_endpoint               |                           |
  |------------------------------>|                           |
  |               |               |                           |
  |               |               |  POST token_endpoint      |
  |               |               |  resource_token,          |
  |               |               |  login_hint, tenant       |
  |               |               |-------------------------->|
  |               |               |                           |
  |               |               |  202 Accepted             |
  |               |               |  requirement=interaction  |
  |               |               |  url, code                |
  |               |               |<--------------------------|
  |               |               |                           |
  |  direct to {url}?code={code}  |                           |
  |<------------------------------|                           |
  |               |               |                           |
  |  authenticate at PS           |                           |
  |------------------------------------------------------>---|
  |               |               |                           |
  |               |               |  GET pending URL          |
  |               |               |-------------------------->|
  |               |               |  200 OK, auth_token       |
  |               |               |<--------------------------|
  |               |               |                           |
  |  redirect to start_path       |                           |
  |<------------------------------|                           |
]]>
</sourcecode>
</figure>
<t>The third party does not need to be the PS. Any party that knows the agent's or resource's <tt>login_endpoint</tt> (from metadata) can initiate the flow. The agent or resource treats the redirect as untrusted input — it verifies the PS through metadata discovery and initiates a signed flow.</t>
</section>

<section anchor="security-considerations-for-third-party-login"><name>Security Considerations for Third-Party Login</name>

<ul spacing="compact">
<li>The <tt>login_endpoint</tt> does not carry any tokens, codes, or pre-authorized state. The agent or resource initiates a standard signed flow with the PS, which independently authenticates the user.</li>
<li>The <tt>start_path</tt> parameter MUST be validated as a relative path on the recipient's own origin to prevent open redirect attacks.</li>
<li>The <tt>ps</tt> parameter is untrusted input. The agent or resource MUST discover and verify the PS via its well-known metadata before proceeding.</li>
</ul>
</section>
</section>

<section anchor="protocol-primitives"><name>Protocol Primitives</name>
<t>This section defines the common mechanisms used across all AAuth endpoints: requirement responses, capabilities, deferred responses, error responses, scopes, token revocation, HTTP message signatures, key discovery, identifiers, and metadata documents.</t>

<section anchor="aauth-capabilities"><name>AAuth-Capabilities Request Header</name>
<t>Agents use the <tt>AAuth-Capabilities</tt> request header to declare which protocol capabilities they can handle. This allows resources and PSes to tailor their responses — for example, a resource that sees <tt>interaction</tt> in the capabilities knows it can send <tt>requirement=interaction</tt>, whereas a resource that does not see <tt>interaction</tt> knows it must use an alternative path (such as issuing a resource token for three-party mode).</t>
<t>The <tt>AAuth-Capabilities</tt> header field is a List (<xref target="RFC8941"/>, Section 3.1) of Tokens.</t>

<sourcecode type="http"><![CDATA[AAuth-Capabilities: interaction, clarification, payment
]]>
</sourcecode>
<t>This specification defines the following capability values:</t>
<table>
<thead>
<tr>
<th>Value</th>
<th>Meaning</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>interaction</tt></td>
<td>Agent can get a user to a URL — either directly (user is present) or via its PS's interaction endpoint</td>
</tr>

<tr>
<td><tt>clarification</tt></td>
<td>Agent can engage in back-and-forth clarification chat</td>
</tr>

<tr>
<td><tt>payment</tt></td>
<td>Agent can handle <tt>402</tt> payment flows — either directly or via its PS's interaction endpoint</td>
</tr>
</tbody>
</table><t>The agent determines its capabilities by combining what it can do directly with what its PS can do on its behalf. When the agent has a PS and has created a mission, the mission approval response includes a <tt>capabilities</tt> array listing what the PS can handle for this user/session <xref target="mission-approval"/>. The agent unions its own capabilities with the PS's capabilities to produce the <tt>AAuth-Capabilities</tt> header value.</t>
<t>Agents SHOULD include the <tt>AAuth-Capabilities</tt> header on signed requests to resources. The header is not used on requests to PS endpoints — the PS learns the agent's capabilities through the mission approval flow. Recipients MUST ignore unrecognized capability values. When the header is absent, recipients MUST NOT assume any capabilities — the agent may not support interaction, clarification, or payment flows.</t>
</section>

<section anchor="scopes"><name>Scopes</name>
<t>Scopes define what an agent is authorized to do at a resource. AAuth uses two categories of scope values:</t>

<ul spacing="compact">
<li><strong>Resource scopes</strong>: Resource-specific authorization grants (e.g., <tt>data.read</tt>, <tt>data.write</tt>, <tt>data.delete</tt>). Each resource defines its own scope values and publishes human-readable descriptions in its metadata (<tt>scope_descriptions</tt>). Resources that already define OAuth scopes SHOULD use the same scope values in AAuth.</li>
<li><strong>Identity scopes</strong>: Requests for user identity claims following <xref target="OpenID.Core"/> (e.g., <tt>openid</tt>, <tt>profile</tt>, <tt>email</tt>, <tt>address</tt>, <tt>phone</tt>). When identity scopes are present, the auth token includes the corresponding identity claims. Enterprise identity extensions (e.g., <tt>org</tt>, <tt>groups</tt>, <tt>roles</tt>) follow <xref target="OpenID.Enterprise"/>.</li>
</ul>
<t>A resource token MUST only include resource scopes that the resource has defined in its <tt>scope_descriptions</tt> metadata, and identity scopes that the PS has declared in its <tt>scopes_supported</tt> metadata. This ensures all parties can interpret and present the requested scopes.</t>
<t>Scopes appear in three places in the protocol:</t>

<ol spacing="compact">
<li><strong>Resource token</strong> (<tt>scope</tt>): The scope the resource is willing to grant, as determined by the resource based on the agent's request at the authorization endpoint.</li>
<li><strong>Auth token</strong> (<tt>scope</tt>): The scope actually granted. The auth token's scope MUST NOT be broader than the resource token's scope.</li>
<li><strong>Authorization endpoint request</strong> (<tt>scope</tt>): The scope the agent is requesting from the resource.</li>
</ol>
<t>The PS evaluates requested scopes against mission context (if present) and user consent. The AS evaluates scopes against resource policy. Either party may narrow the granted scope.</t>
</section>

<section anchor="requirement-responses"><name>Requirement Responses</name>
<t>Servers use the <tt>AAuth-Requirement</tt> response header to indicate protocol-level requirements to agents. The header MAY be sent with <tt>401 Unauthorized</tt> or <tt>202 Accepted</tt> responses. A <tt>401</tt> response indicates that authorization is required. A <tt>202</tt> response indicates that the request is pending and additional action is required — either user interaction (<tt>requirement=interaction</tt>) or third-party approval (<tt>requirement=approval</tt>).</t>
<t><tt>AAuth-Requirement</tt> and <tt>WWW-Authenticate</tt> are independent header fields; a response MAY include both. A client that understands AAuth processes <tt>AAuth-Requirement</tt>; a legacy client processes <tt>WWW-Authenticate</tt>. Neither header's presence invalidates the other.</t>
<t>The header MAY also be sent with <tt>402 Payment Required</tt> when a server requires both authorization and payment. The <tt>AAuth-Requirement</tt> conveys the authorization requirement; the payment requirement is conveyed by a separate mechanism such as x402 <xref target="x402"/> or the Machine Payment Protocol (MPP) (<xref target="I-D.ryan-httpauth-payment"/>).</t>

<section anchor="aauth-requirement-header-structure"><name>AAuth-Requirement Header Structure</name>
<t>The <tt>AAuth-Requirement</tt> header field is a Dictionary (<xref target="RFC8941"/>, Section 3.2). It MUST contain the following member:</t>

<ul spacing="compact">
<li><tt>requirement</tt>: A Token (<xref target="RFC8941"/>, Section 3.3.4) indicating the requirement type.</li>
</ul>
<t>Additional members are defined per requirement value. Recipients MUST ignore unknown members.</t>
<t>Example:</t>

<sourcecode type="http"><![CDATA[AAuth-Requirement: requirement=auth-token; resource-token="eyJ..."
]]>
</sourcecode>
</section>

<section anchor="requirement-values"><name>Requirement Values</name>
<t>The <tt>requirement</tt> value is an extension point. This document defines the following values:</t>
<table>
<thead>
<tr>
<th>Value</th>
<th>Status Code</th>
<th>Meaning</th>
<th align="center">Resource</th>
<th align="center">PS</th>
<th align="center">AS</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>auth-token</tt></td>
<td><tt>401</tt></td>
<td>Auth token required for resource access</td>
<td align="center">Y</td>
<td align="center"/>
<td align="center"/>
</tr>

<tr>
<td><tt>interaction</tt></td>
<td><tt>202</tt></td>
<td>User action required at an interaction endpoint</td>
<td align="center">Y</td>
<td align="center">Y</td>
<td align="center">Y</td>
</tr>

<tr>
<td><tt>approval</tt></td>
<td><tt>202</tt></td>
<td>Approval pending, poll for result</td>
<td align="center">Y</td>
<td align="center">Y</td>
<td align="center">Y</td>
</tr>

<tr>
<td><tt>clarification</tt></td>
<td><tt>202</tt></td>
<td>Question posed to the recipient</td>
<td align="center">Y</td>
<td align="center">Y</td>
<td align="center">Y</td>
</tr>

<tr>
<td><tt>claims</tt></td>
<td><tt>202</tt></td>
<td>Identity claims required</td>
<td align="center"/>
<td align="center"/>
<td align="center">Y</td>
</tr>
</tbody>
</table><t>The <tt>auth-token</tt> requirement is defined in <xref target="requirement-auth-token"/>; the <tt>interaction</tt> and <tt>approval</tt> requirements are defined in this section;  <tt>clarification</tt> in <xref target="requirement-clarification"/>; and <tt>claims</tt> in <xref target="requirement-claims"/>.</t>
</section>

<section anchor="interaction-required"><name>Interaction Required</name>
<t>When a server requires user action — such as authentication, consent, payment approval, or any decision requiring a human in the loop — it returns a <tt>202 Accepted</tt> response:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 202 Accepted
AAuth-Requirement:
    requirement=interaction;
    url="https://example.com/interact";
    code="A1B2-C3D4"
Location: /pending/f7a3b9c
Retry-After: 0
]]>
</sourcecode>
<t>The <tt>AAuth-Requirement</tt> header MUST include the following parameters:</t>

<ul spacing="compact">
<li><tt>url</tt> (String): The interaction URL where the user completes the required action. MUST use the <tt>https</tt> scheme and MUST NOT contain query or fragment components.</li>
<li><tt>code</tt> (String): An interaction code that links the agent's pending request to the user's session at the interaction URL.</li>
</ul>
<t>The response MUST also include:</t>

<ul spacing="compact">
<li><tt>Location</tt>: A URL the agent polls (with GET) for a terminal response.</li>
<li><tt>Retry-After</tt>: Recommended polling interval in seconds.</li>
</ul>
<t>The agent constructs a user-facing URL by appending the code as a query parameter: <tt>{url}?code={code}</tt>. The agent then directs the user to this URL using one of:</t>

<ul spacing="compact">
<li><strong>Browser redirect</strong>: The agent opens the URL in the user's browser.</li>
<li><strong>Display code</strong>: The agent displays the <tt>url</tt> and <tt>code</tt> for the user to enter manually. The agent MAY also render the constructed URL as a QR code for the user to scan with their phone.</li>
</ul>
<t>After directing the user, the agent polls the <tt>Location</tt> URL with GET requests, respecting the <tt>Retry-After</tt> interval. A <tt>202</tt> response means the request is still pending. A non-<tt>202</tt> response is terminal — <tt>200</tt> indicates success, <tt>403</tt> indicates denial, and <tt>408</tt> indicates timeout.</t>

<sourcecode type="ascii-art"><![CDATA[Agent                        User                         Server
  |                            |                             |
  |  202 Accepted                                            |
  |  AAuth-Requirement:                                      |
  |    requirement=interaction;                              |
  |    url="..."; code="..."                                 |
  |  Location: /pending/...                                  |
  |<---------------------------------------------------------|
  |                            |                             |
  |  open {url}?code={code}    |                             |
  |  (or display code / QR)    |                             |
  |--------------------------->|                             |
  |                            |                             |
  |                            |  {url}?code={code}          |
  |                            |---------------------------->|
  |                            |                             |
  |                            |  user completes action      |
  |                            |<----------------------------|
  |                            |                             |
  |  GET /pending/...                                        |
  |--------------------------------------------------------->|
  |                            |                             |
  |  200 OK                                                  |
  |<---------------------------------------------------------|
]]>
</sourcecode>
<t><strong>Use cases:</strong> User login, consent, payment confirmation, document review, CAPTCHA, any workflow requiring human action.</t>
</section>

<section anchor="approval-pending"><name>Approval Pending</name>
<t>When a server is obtaining approval from another party without requiring the agent to direct a user — for example, via push notification, email, or administrator review:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 202 Accepted
AAuth-Requirement: requirement=approval
Location: /pending/f7a3b9c
Retry-After: 30
]]>
</sourcecode>
<t>The response MUST include <tt>Location</tt> and <tt>Retry-After</tt>. The agent polls the <tt>Location</tt> URL with GET requests until a terminal response is received. No user action is required at the agent side. The same terminal response codes apply as for <tt>interaction</tt>.</t>
<t><strong>Use cases:</strong> Administrator approval, resource owner consent, compliance review, direct user authorization via established communication channel.</t>
</section>
</section>

<section anchor="deferred-responses"><name>Deferred Responses</name>
<t>Any endpoint in AAuth — whether a PS token endpoint, AS token endpoint, or resource endpoint — MAY return a <tt>202 Accepted</tt> response (<xref target="RFC9110"/>) when it cannot immediately resolve a request. This is a first-class protocol primitive, not a special case. Agents MUST handle <tt>202</tt> responses regardless of the nature of the original request.</t>

<section anchor="initial-request"><name>Initial Request</name>
<t>The agent makes a request and signals its willingness to wait using the <tt>Prefer</tt> header (<xref target="RFC7240"/>):</t>

<sourcecode type="http"><![CDATA[POST /token HTTP/1.1
Host: auth.example
Content-Type: application/json
Prefer: wait=45
Signature-Input: sig=("@method" "@authority"
    "@path" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "resource_token": "eyJhbGc..."
}
]]>
</sourcecode>
</section>

<section anchor="pending-response"><name>Pending Response</name>
<t>When the server cannot resolve the request within the wait period:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 202 Accepted
Location: /pending/f7a3b9c
Retry-After: 0
Cache-Control: no-store
Content-Type: application/json

{
  "status": "pending"
}
]]>
</sourcecode>
<t>Headers:</t>

<ul spacing="compact">
<li><tt>Location</tt> (REQUIRED): The pending URL. The <tt>Location</tt> URL MUST be on the same origin as the responding server.</li>
<li><tt>Retry-After</tt> (REQUIRED): Seconds the agent SHOULD wait before polling. <tt>0</tt> means retry immediately.</li>
<li><tt>Cache-Control: no-store</tt> (REQUIRED): Prevents caching of pending responses.</li>
<li><tt>AAuth-Requirement</tt> (OPTIONAL): Present when user interaction or approval is required. The <tt>url</tt> and <tt>code</tt> parameters are defined in <xref target="requirement-responses"/>.</li>
</ul>
<t>Body fields:</t>

<ul spacing="compact">
<li><tt>status</tt> (REQUIRED): <tt>"pending"</tt> while the request is waiting. <tt>"interacting"</tt> when the user has arrived at the interaction endpoint. Agents MUST treat unrecognized <tt>status</tt> values as <tt>"pending"</tt> and continue polling.</li>
</ul>
<t>Additional body fields may be present depending on the <tt>AAuth-Requirement</tt> value — for example, <tt>clarification</tt> and <tt>timeout</tt> with <tt>requirement=clarification</tt>, or <tt>required_claims</tt> with <tt>requirement=claims</tt>. See the specific requirement definitions for details.</t>
</section>

<section anchor="polling-with-get"><name>Polling with GET</name>
<t>After receiving a <tt>202</tt>, the agent switches to <tt>GET</tt> for all subsequent requests to the <tt>Location</tt> URL. The agent does NOT resend the original request body. <strong>Exception</strong>: During clarification chat, the agent uses <tt>POST</tt> to deliver a clarification response.</t>
<t>The agent MUST respect <tt>Retry-After</tt> values. If a <tt>Retry-After</tt> header is not present, the default polling interval is 5 seconds. If the server responds with <tt>429 Too Many Requests</tt>, the agent MUST increase its polling interval by 5 seconds (linear backoff, following the pattern in <xref target="RFC8628"/>, Section 3.5). The <tt>Prefer: wait=N</tt> header (<xref target="RFC7240"/>) MAY be included on polling requests to signal the agent's willingness to wait for a long-poll response.</t>
</section>

<section anchor="deferred-response-state-machine"><name>Deferred Response State Machine</name>
<t>The following state machine applies to any AAuth endpoint that returns a <tt>202 Accepted</tt> response — including PS token endpoints, AS token endpoints, and resource endpoints during call chaining. A non-<tt>202</tt> response terminates polling.</t>

<artwork><![CDATA[Initial request (with Prefer: wait=N)
    |
    +-- 200 --> done — process response body
    +-- 202 --> note Location URL, check requirement/code
    +-- 400 --> invalid request — check error field, fix and retry
    +-- 401 --> invalid signature — check credentials;
    |           obtain auth token if resource challenge
    +-- 402 --> payment required (settle payment, poll Location)
    +-- 500 --> server error — start over
    +-- 503 --> back off per Retry-After, retry
               |
               GET Location (with Prefer: wait=N)
               |
               +-- 200 --> done — process response body
               +-- 202 --> continue polling (check status/clarification)
               |           status=interacting → stop prompting user
               +-- 403 --> denied or abandoned — surface to user
               +-- 408 --> expired — MAY initiate a fresh request
               +-- 410 --> gone — MUST NOT retry
               +-- 429 --> slow down — increase interval by 5s
               +-- 500 --> server error — start over
               +-- 503 --> temporarily unavailable
                           back off per Retry-After
]]>
</artwork>
</section>
</section>

<section anchor="error-responses"><name>Error Responses</name>

<section anchor="authentication-errors"><name>Authentication Errors</name>
<t>A <tt>401</tt> response from any AAuth endpoint uses the <tt>Signature-Error</tt> header as defined in (<xref target="I-D.hardt-httpbis-signature-key"/>).</t>
</section>

<section anchor="error-response-format"><name>Token Endpoint Error Response Format</name>
<t>Token endpoint errors use <tt>Content-Type: application/json</tt> (<xref target="RFC8259"/>) with the following members:</t>

<ul spacing="compact">
<li><tt>error</tt> (REQUIRED): String. A single error code.</li>
<li><tt>error_description</tt> (OPTIONAL): String. A human-readable description.</li>
</ul>
</section>

<section anchor="token-endpoint-error-codes"><name>Token Endpoint Error Codes</name>
<table>
<thead>
<tr>
<th>Error</th>
<th>Status</th>
<th>Meaning</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>invalid_request</tt></td>
<td>400</td>
<td>Malformed JSON, missing required fields</td>
</tr>

<tr>
<td><tt>invalid_agent_token</tt></td>
<td>400</td>
<td>Agent token malformed or signature verification failed</td>
</tr>

<tr>
<td><tt>expired_agent_token</tt></td>
<td>400</td>
<td>Agent token has expired</td>
</tr>

<tr>
<td><tt>invalid_resource_token</tt></td>
<td>400</td>
<td>Resource token malformed or signature verification failed</td>
</tr>

<tr>
<td><tt>expired_resource_token</tt></td>
<td>400</td>
<td>Resource token has expired</td>
</tr>

<tr>
<td><tt>interaction_required</tt></td>
<td>403</td>
<td>User interaction is needed but no interaction channel is available — the PS cannot reach the user and the agent does not have the <tt>interaction</tt> capability</td>
</tr>

<tr>
<td><tt>server_error</tt></td>
<td>500</td>
<td>Internal error</td>
</tr>
</tbody>
</table></section>

<section anchor="polling-error-codes"><name>Polling Error Codes</name>
<table>
<thead>
<tr>
<th>Error</th>
<th>Status</th>
<th>Meaning</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>denied</tt></td>
<td>403</td>
<td>User or approver explicitly denied the request</td>
</tr>

<tr>
<td><tt>abandoned</tt></td>
<td>403</td>
<td>Interaction code was used but user did not complete</td>
</tr>

<tr>
<td><tt>expired</tt></td>
<td>408</td>
<td>Timed out</td>
</tr>

<tr>
<td><tt>invalid_code</tt></td>
<td>410</td>
<td>Interaction code not recognized or already consumed</td>
</tr>

<tr>
<td><tt>slow_down</tt></td>
<td>429</td>
<td>Polling too frequently — increase interval by 5 seconds</td>
</tr>

<tr>
<td><tt>server_error</tt></td>
<td>500</td>
<td>Internal error</td>
</tr>
</tbody>
</table></section>
</section>

<section anchor="token-revocation"><name>Token Revocation</name>
<t>Any AAuth server that issues tokens MAY provide a revocation endpoint. The endpoint accepts a signed POST with the <tt>jti</tt> of the token to revoke. The server identifies the token from the <tt>jti</tt> and its own records — no token type is needed since the <tt>jti</tt> is unique within the issuer's namespace.</t>
<t><strong>Request:</strong></t>

<sourcecode type="http"><![CDATA[POST /revoke HTTP/1.1
Host: ps.example
Content-Type: application/json
Signature-Input: sig=("@method" "@authority"
    "@path" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

{
  "jti": "unique-token-identifier"
}
]]>
</sourcecode>
<t><strong>Response:</strong> <tt>200 OK</tt> if the token was revoked or was already invalid. <tt>404</tt> if the <tt>jti</tt> is not recognized.</t>
<t>Revocation provides real-time termination of access. The PS or AS calls the revocation endpoint of the resource that a token was issued for, passing the <tt>jti</tt> of the auth token to revoke. The following revocation scenarios are supported:</t>

<ul spacing="compact">
<li><strong>PS revokes an auth token it issued</strong> (three-party): The PS calls the resource's revocation endpoint with the auth token's <tt>jti</tt>.</li>
<li><strong>PS revokes an auth token it provided</strong> (four-party): The PS calls the resource's revocation endpoint with the auth token's <tt>jti</tt>. The PS MAY also notify the AS.</li>
<li><strong>AS revokes an auth token it issued</strong>: The AS calls the resource's revocation endpoint with the auth token's <tt>jti</tt>.</li>
<li><strong>PS revokes a mission</strong>: The PS marks the mission as revoked. All subsequent token requests referencing that mission's <tt>s256</tt> are denied. The PS SHOULD revoke outstanding auth tokens issued under the mission.</li>
<li><strong>Agent server stops issuing agent tokens</strong>: The agent server decides not to issue new agent tokens to the agent. Existing agent tokens expire naturally. This is part of the regular token lifecycle — all tokens have limited lifetimes and require periodic re-issuance, which provides a natural policy re-evaluation point.</li>
</ul>
<t>Revocation endpoints are advertised in server metadata as <tt>revocation_endpoint</tt>. Resources that accept revocation requests MUST verify the caller's identity via HTTP Message Signatures and MUST only accept revocation from the issuer of the token being revoked or from a trusted PS.</t>
<t>Auth tokens are short-lived (maximum 1 hour) and proof-of-possession (useless without the bound signing key). All AAuth tokens have limited lifetimes — agent tokens, resource tokens, and auth tokens all expire and require re-issuance. Each re-issuance is a policy evaluation point where the issuer can deny renewal. This natural expiration cycle, combined with real-time revocation, provides layered access control.</t>
</section>

<section anchor="http-message-signatures-profile"><name>HTTP Message Signatures Profile</name>
<t>This section profiles HTTP Message Signatures (<xref target="RFC9421"/>) for use with AAuth. Signing requirements (what the agent does) and verification requirements (what the server does) are specified separately.</t>

<section anchor="signature-algorithms"><name>Signature Algorithms</name>
<t>Agents and resources MUST support EdDSA using Ed25519 (<xref target="RFC8032"/>). Agents and resources SHOULD support ECDSA using P-256 with deterministic signatures (<xref target="RFC6979"/>). The <tt>alg</tt> parameter in the JWK (<xref target="RFC7517"/>) key representation identifies the algorithm. See the IANA JSON Web Signature and Encryption Algorithms registry (<xref target="RFC7518"/>, Section 7.1) for the full list of algorithm identifiers.</t>
</section>

<section anchor="keying-material"><name>Keying Material</name>
<t>The signing key is conveyed in the <tt>Signature-Key</tt> header (<xref target="I-D.hardt-httpbis-signature-key"/>). The Signature-Key scheme determines how the server obtains the public key:</t>

<ul spacing="compact">
<li>For <tt>pseudonym</tt>: the agent uses <tt>scheme=hwk</tt> (inline public key) or <tt>scheme=jkt-jwt</tt> (delegation from a hardware-backed key).</li>
<li>For <tt>identity</tt>: the agent uses <tt>scheme=jwks_uri</tt> (JWKS endpoint) or <tt>scheme=jwt</tt> (JWT with public key in <tt>cnf</tt> claim).</li>
</ul>
<t>See the Signature-Key specification (<xref target="I-D.hardt-httpbis-signature-key"/>) for scheme definitions, key discovery, and verification procedures.</t>
</section>

<section anchor="signing-agent"><name>Signing (Agent)</name>
<t>The agent creates an HTTP Message Signature (<xref target="RFC9421"/>) on each request, including the following headers:</t>

<ul spacing="compact">
<li><tt>Signature-Key</tt>: Public key or key reference for signature verification</li>
<li><tt>Signature-Input</tt>: Signature metadata including covered components</li>
<li><tt>Signature</tt>: The HTTP message signature</li>
</ul>

<section anchor="covered-components"><name>Covered Components</name>
<t>The signature MUST cover the following derived components and header fields:</t>

<ul spacing="compact">
<li><tt>@method</tt>: The HTTP request method (<xref target="RFC9421"/>, Section 2.2.1)</li>
<li><tt>@authority</tt>: The target host (<xref target="RFC9421"/>, Section 2.2.3)</li>
<li><tt>@path</tt>: The request path (<xref target="RFC9421"/>, Section 2.2.6)</li>
<li><tt>signature-key</tt>: The Signature-Key header value</li>
</ul>
<t>Servers MAY require additional covered components (e.g., <tt>content-digest</tt> (<xref target="RFC9530"/>) for request body integrity). The agent learns about additional requirements from server metadata or from an <tt>invalid_input</tt> error response that includes <tt>required_input</tt>.</t>
</section>

<section anchor="signature-parameters"><name>Signature Parameters</name>
<t>The <tt>Signature-Input</tt> header (<xref target="RFC9421"/>, Section 4.1) MUST include the following parameters:</t>

<ul spacing="compact">
<li><tt>created</tt>: Signature creation timestamp as an Integer (Unix time). The agent MUST set this to the current time.</li>
</ul>
</section>
</section>

<section anchor="verification"><name>Verification (Server)</name>
<t>When a server receives a signed request, it MUST perform the following steps. Any failure MUST result in a <tt>401</tt> response with the appropriate <tt>Signature-Error</tt> header (<xref target="I-D.hardt-httpbis-signature-key"/>).</t>

<ol spacing="compact">
<li>Extract the <tt>Signature</tt>, <tt>Signature-Input</tt>, and <tt>Signature-Key</tt> headers. If any are missing, return <tt>invalid_request</tt>.</li>
<li>Verify that the <tt>Signature-Input</tt> covers the required components defined in <xref target="covered-components"/>. If the server requires additional components, verify those are covered as well. If not, return <tt>invalid_input</tt> with <tt>required_input</tt>.</li>
<li>Verify the <tt>created</tt> parameter is present and within the server's signature validity window of the server's current time. The default window is 60 seconds. Servers MAY advertise a different window via their metadata (e.g., <tt>signature_window</tt> in resource metadata). Reject with <tt>invalid_signature</tt> if outside this window. Servers and agents SHOULD synchronize their clocks using NTP (<xref target="RFC5905"/>).</li>
<li>Determine the signature algorithm from the <tt>alg</tt> parameter in the key. If the algorithm is not supported, return <tt>unsupported_algorithm</tt>.</li>
<li>Obtain the public key from the <tt>Signature-Key</tt> header according to the scheme, as specified in (<xref target="I-D.hardt-httpbis-signature-key"/>). Return <tt>invalid_key</tt> if the key cannot be parsed, <tt>unknown_key</tt> if the key is not found at the <tt>jwks_uri</tt>, <tt>invalid_jwt</tt> if a JWT scheme fails verification, or <tt>expired_jwt</tt> if the JWT has expired.</li>
<li>Verify the HTTP Message Signature (<xref target="RFC9421"/>) using the obtained public key and determined algorithm. Return <tt>invalid_signature</tt> if verification fails.</li>
</ol>
</section>
</section>

<section anchor="jwks-discovery"><name>JWKS Discovery and Caching</name>
<t>All AAuth token verification — agent tokens, resource tokens, and auth tokens — requires discovering the issuer's signing keys via the <tt>{iss}/.well-known/{dwk}</tt> pattern defined in the HTTP Signature Keys specification (<xref target="I-D.hardt-httpbis-signature-key"/>).</t>
<t>Implementations MUST cache JWKS responses and SHOULD respect HTTP cache headers (<tt>Cache-Control</tt>, <tt>Expires</tt>) returned by the JWKS endpoint. When an implementation encounters an unknown <tt>kid</tt> in a JWT header, it SHOULD refresh the cached JWKS for that issuer to support key rotation. To prevent abuse, implementations MUST NOT fetch a given issuer's JWKS more frequently than once per minute. If a JWKS fetch fails, implementations SHOULD use the cached JWKS if available and SHOULD retry with exponential backoff. Cached JWKS entries SHOULD be discarded after a maximum of 24 hours regardless of cache headers, to ensure removed keys are no longer trusted.</t>
</section>

<section anchor="identifiers-and-discovery"><name>Identifiers</name>

<section anchor="server-identifiers"><name>Server Identifiers</name>
<t>The <tt>issuer</tt> values in metadata documents that identify agent servers, resources, access servers, and person servers MUST conform to the following:</t>

<ul spacing="compact">
<li>MUST use the <tt>https</tt> scheme</li>
<li>MUST contain only scheme and host (no port, path, query, or fragment)</li>
<li>MUST NOT include a trailing slash</li>
<li>MUST be lowercase</li>
<li>Internationalized domain names MUST use the ASCII-Compatible Encoding (ACE) form (A-labels) as defined in <xref target="RFC5890"/></li>
</ul>
<t>Valid identifiers:</t>

<ul spacing="compact">
<li><tt>https://agent.example</tt></li>
<li><tt>https://xn--nxasmq6b.example</tt> (internationalized domain in ACE form)</li>
</ul>
<t>Invalid identifiers:</t>

<ul spacing="compact">
<li><tt>http://agent.example</tt> (not HTTPS)</li>
<li><tt>https://Agent.Example</tt> (not lowercase)</li>
<li><tt>https://agent.example:8443</tt> (contains port)</li>
<li><tt>https://agent.example/v1</tt> (contains path)</li>
<li><tt>https://agent.example/</tt> (trailing slash)</li>
</ul>
<t>Implementations MUST perform exact string comparison on server identifiers.</t>
</section>

<section anchor="endpoint-urls"><name>Endpoint URLs</name>
<t>The <tt>token_endpoint</tt>, <tt>authorization_endpoint</tt>, <tt>mission_endpoint</tt>, and <tt>callback_endpoint</tt> values MUST conform to the following:</t>

<ul spacing="compact">
<li>MUST use the <tt>https</tt> scheme</li>
<li>MUST NOT contain a fragment</li>
<li>MUST NOT contain a query string</li>
</ul>
<t>When <tt>localhost_callback_allowed</tt> is <tt>true</tt> in the agent's metadata, the agent MAY use a localhost callback URL as the <tt>callback</tt> parameter to the interaction endpoint.</t>
</section>

<section anchor="other-urls"><name>Other URLs</name>
<t>The <tt>jwks_uri</tt>, <tt>tos_uri</tt>, <tt>policy_uri</tt>, <tt>logo_uri</tt>, and <tt>logo_dark_uri</tt> values MUST use the <tt>https</tt> scheme.</t>
</section>
</section>

<section anchor="metadata-documents"><name>Metadata Documents</name>
<t>Participants publish metadata at well-known URLs (<xref target="RFC8615"/>) to enable discovery.</t>

<section anchor="agent-server-metadata"><name>Agent Server Metadata</name>
<t>Published at <tt>/.well-known/aauth-agent.json</tt>:</t>

<sourcecode type="json"><![CDATA[{
  "issuer": "https://agent.example",
  "jwks_uri": "https://agent.example/.well-known/jwks.json",
  "client_name": "Example AI Assistant",
  "logo_uri": "https://agent.example/logo.png",
  "logo_dark_uri": "https://agent.example/logo-dark.png",
  "callback_endpoint": "https://agent.example/callback",
  "localhost_callback_allowed": true,
  "tos_uri": "https://agent.example/tos",
  "policy_uri": "https://agent.example/privacy"
}
]]>
</sourcecode>
<t>Fields:</t>

<ul spacing="compact">
<li><tt>issuer</tt> (REQUIRED): The agent server's HTTPS URL (the <tt>domain</tt> in agent identifiers it issues). This is the value placed in the <tt>iss</tt> claim of agent tokens.</li>
<li><tt>jwks_uri</tt> (REQUIRED): URL to the agent server's JSON Web Key Set</li>
<li><tt>client_name</tt> (OPTIONAL): Human-readable agent name (per <xref target="RFC7591"/>)</li>
<li><tt>logo_uri</tt> (OPTIONAL): URL to agent logo (per <xref target="RFC7591"/>)</li>
<li><tt>logo_dark_uri</tt> (OPTIONAL): URL to agent logo for dark backgrounds</li>
<li><tt>callback_endpoint</tt> (OPTIONAL): The agent's HTTPS callback endpoint URL</li>
<li><tt>login_endpoint</tt> (OPTIONAL): URL where third parties can direct users to initiate authentication <xref target="third-party-login"/></li>
<li><tt>localhost_callback_allowed</tt> (OPTIONAL): Boolean. Default: <tt>false</tt>.</li>
<li><tt>tos_uri</tt> (OPTIONAL): URL to terms of service (per <xref target="RFC7591"/>)</li>
<li><tt>policy_uri</tt> (OPTIONAL): URL to privacy policy (per <xref target="RFC7591"/>)</li>
</ul>
</section>

<section anchor="ps-metadata"><name>Person Server Metadata</name>
<t>Published at <tt>/.well-known/aauth-person.json</tt>:</t>

<sourcecode type="json"><![CDATA[{
  "issuer": "https://ps.example",
  "token_endpoint": "https://ps.example/token",
  "mission_endpoint": "https://ps.example/mission",
  "permission_endpoint": "https://ps.example/permission",
  "audit_endpoint": "https://ps.example/audit",
  "interaction_endpoint": "https://ps.example/interaction",
  "mission_control_endpoint": "https://ps.example/mission-control",
  "jwks_uri": "https://ps.example/.well-known/jwks.json"
}
]]>
</sourcecode>
<t>Fields:</t>

<ul spacing="compact">
<li><tt>issuer</tt> (REQUIRED): The PS's HTTPS URL. MUST match the URL used to fetch the metadata document. This is the value placed in the <tt>iss</tt> claim of JWTs issued by the PS.</li>
<li><tt>token_endpoint</tt> (REQUIRED): URL where agents send token requests</li>
<li><tt>mission_endpoint</tt> (OPTIONAL): URL for mission lifecycle operations (proposal, status). Present when the PS supports missions.</li>
<li><tt>permission_endpoint</tt> (OPTIONAL): URL where agents request permission for actions not governed by a remote resource <xref target="permission-endpoint"/></li>
<li><tt>audit_endpoint</tt> (OPTIONAL): URL where agents log actions performed <xref target="audit-endpoint"/></li>
<li><tt>interaction_endpoint</tt> (OPTIONAL): URL where agents relay interactions to the user through the PS <xref target="interaction-endpoint"/></li>
<li><tt>mission_control_endpoint</tt> (OPTIONAL): URL for mission administrative interface</li>
<li><tt>revocation_endpoint</tt> (OPTIONAL): URL where authorized parties can revoke tokens <xref target="token-revocation"/></li>
<li><tt>jwks_uri</tt> (REQUIRED): URL to the PS's JSON Web Key Set</li>
<li><tt>scopes_supported</tt> (RECOMMENDED): Array of scope values the PS supports, including identity scopes (e.g., <tt>openid</tt>, <tt>profile</tt>, <tt>email</tt>) and enterprise scopes (e.g., <tt>org</tt>, <tt>groups</tt>, <tt>roles</tt>)</li>
<li><tt>claims_supported</tt> (RECOMMENDED): Array of identity claim names the PS can provide (e.g., <tt>sub</tt>, <tt>email</tt>, <tt>name</tt>, <tt>org</tt>)</li>
</ul>
</section>

<section anchor="access-server-metadata"><name>Access Server Metadata</name>
<t>Published at <tt>/.well-known/aauth-access.json</tt>:</t>

<sourcecode type="json"><![CDATA[{
  "issuer": "https://as.resource.example",
  "token_endpoint": "https://as.resource.example/token",
  "jwks_uri": "https://as.resource.example/.well-known/jwks.json"
}
]]>
</sourcecode>
<t>Fields:</t>

<ul spacing="compact">
<li><tt>issuer</tt> (REQUIRED): The AS's HTTPS URL. MUST match the URL used to fetch the metadata document. This is the value placed in the <tt>iss</tt> claim of auth tokens.</li>
<li><tt>token_endpoint</tt> (REQUIRED): URL where PSes send token requests</li>
<li><tt>revocation_endpoint</tt> (OPTIONAL): URL where authorized parties can revoke tokens <xref target="token-revocation"/></li>
<li><tt>jwks_uri</tt> (REQUIRED): URL to the AS's JSON Web Key Set</li>
</ul>
</section>

<section anchor="resource-metadata"><name>Resource Metadata</name>
<t>Published at <tt>/.well-known/aauth-resource.json</tt>:</t>

<sourcecode type="json"><![CDATA[{
  "issuer": "https://resource.example",
  "jwks_uri": "https://resource.example/.well-known/jwks.json",
  "client_name": "Example Data Service",
  "logo_uri": "https://resource.example/logo.png",
  "logo_dark_uri": "https://resource.example/logo-dark.png",
  "authorization_endpoint": "https://resource.example/authorize",
  "scope_descriptions": {
    "data.read": "Read access to your data and documents",
    "data.write": "Create and update your data and documents",
    "data.delete": "Permanently delete your data and documents"
  },
  "additional_signature_components": ["content-type", "content-digest"]
}
]]>
</sourcecode>
<t>Fields:</t>

<ul spacing="compact">
<li><tt>issuer</tt> (REQUIRED): The resource's HTTPS URL. This is the value placed in the <tt>iss</tt> claim of resource tokens.</li>
<li><tt>jwks_uri</tt> (REQUIRED): URL to the resource's JSON Web Key Set</li>
<li><tt>client_name</tt> (OPTIONAL): Human-readable resource name (per <xref target="RFC7591"/>)</li>
<li><tt>logo_uri</tt> (OPTIONAL): URL to resource logo (per <xref target="RFC7591"/>)</li>
<li><tt>logo_dark_uri</tt> (OPTIONAL): URL to resource logo for dark backgrounds</li>
<li><tt>authorization_endpoint</tt> (OPTIONAL): URL where agents request authorization <xref target="authorization-endpoint-request"/>. When absent, the resource issues resource tokens and interaction requirements via <tt>401</tt> responses (#requirement-auth-token, #resource-managed-auth).</li>
<li><tt>login_endpoint</tt> (OPTIONAL): URL where third parties can direct users to initiate authentication <xref target="third-party-login"/></li>
<li><tt>scope_descriptions</tt> (OPTIONAL): Object mapping scope values to Markdown strings for consent display. Scope values are resource-specific; resources that already define OAuth scopes SHOULD use the same scope values in AAuth. Identity-related scopes (e.g., <tt>openid</tt>, <tt>profile</tt>, <tt>email</tt>) follow <xref target="OpenID.Core"/>.</li>
<li><tt>signature_window</tt> (OPTIONAL): Integer. The signature validity window in seconds for the <tt>created</tt> timestamp. Default: 60. Resources serving agents with poor clock synchronization (mobile, IoT) MAY advertise a larger value. High-security resources MAY advertise a smaller value.</li>
<li><tt>additional_signature_components</tt> (OPTIONAL): Array of HTTP message component identifiers (<xref target="RFC9421"/>) that agents MUST include in the <tt>Signature-Input</tt> covered components when signing requests to this resource, in addition to the base components required by the HTTP Message Signatures profile (<xref target="I-D.hardt-httpbis-signature-key"/>)</li>
<li><tt>revocation_endpoint</tt> (OPTIONAL): URL where authorized parties can revoke auth tokens for this resource <xref target="token-revocation"/></li>
</ul>
</section>
</section>
</section>

<section anchor="incremental-adoption"><name>Incremental Adoption</name>
<t>AAuth is designed for incremental adoption. Each party — agent, resource, PS, AS — can independently add support. The system works at every partial adoption state. No coordination is required between parties.</t>

<section anchor="agent-adoption-path"><name>Agent Adoption Path</name>
<t>Each step builds on the previous one. An agent that adopts any step gains immediate value.</t>

<ol spacing="compact">
<li><strong>Sign requests with HTTP Message Signatures</strong>: The agent signs requests using the Signature-Key specification (<xref target="I-D.hardt-httpbis-signature-key"/>). Resources that recognize signatures can verify the agent's key and respond with <tt>Accept-Signature</tt> headers. Resources that don't recognize signatures ignore the headers — existing auth mechanisms continue to work.</li>
<li><strong>Obtain an agent token</strong> (<tt>scheme=jwt</tt>, <tt>typ: aa-agent+jwt</tt>): The agent has a full AAuth identity with an <tt>aauth:local@domain</tt> identifier issued by an agent server, providing a stable, managed identity lifecycle. The agent token is presented via the <tt>Signature-Key</tt> header using <tt>scheme=jwt</tt>.</li>
<li><strong>Add a person server</strong> (include <tt>ps</tt> claim in agent token): The agent can obtain auth tokens from its PS directly. Resources in three-party and four-party modes can issue resource tokens targeting the PS. Enables PS-issued auth tokens with user identity, organization membership, and group information.</li>
<li><strong>Add governance</strong> (create a mission): The agent creates a mission at its PS, gaining permissions, audit, PS-relayed interactions, and consent-managed resource access. The mission can be as simple as the user's prompt.</li>
</ol>
</section>

<section anchor="resource-adoption-path"><name>Resource Adoption Path</name>
<t>Each step builds on the previous one. A resource that adopts any step works with agents at all identity levels.</t>

<ol spacing="compact">
<li><strong>Recognize AAuth signatures</strong>: Verify HTTP Message Signatures and respond with <tt>Accept-Signature</tt> headers (<xref target="I-D.hardt-httpbis-signature-key"/>). Resources that don't recognize AAuth ignore the signature headers — existing auth mechanisms continue to work. This is identity-based access.</li>
<li><strong>Manage authorization</strong>: Handle authorization with interaction, consent, or existing infrastructure — via <tt>401</tt> responses, an authorization endpoint, or both. Return <tt>AAuth-Access</tt> headers <xref target="aauth-access"/> for subsequent calls. This is resource-managed access (two-party).</li>
<li><strong>Issue resource tokens to PS</strong>: Read the <tt>ps</tt> claim from the agent token and issue resource tokens with <tt>aud</tt> = PS URL. This is PS-managed access (three-party).</li>
<li><strong>Deploy an access server</strong>: Issue resource tokens with <tt>aud</tt> = AS URL. The PS federates with the AS. This is federated access (four-party).</li>
</ol>
</section>

<section anchor="adoption-matrix"><name>Adoption Matrix</name>
<table>
<thead>
<tr>
<th>Agent</th>
<th>Resource</th>
<th>Mode</th>
<th>What Works</th>
</tr>
</thead>

<tbody>
<tr>
<td>Signed requests</td>
<td>Recognizes signatures</td>
<td>Identity-based</td>
<td>Identity verification, access control by agent identity</td>
</tr>

<tr>
<td>Agent token</td>
<td>Manages authorization</td>
<td>Resource-managed</td>
<td>Resource-handled auth, interaction, <tt>AAuth-Access</tt></td>
</tr>

<tr>
<td>Agent token + <tt>ps</tt></td>
<td>Issues resource tokens</td>
<td>PS-managed</td>
<td>PS-issued auth tokens with user identity, org, groups</td>
</tr>

<tr>
<td>Agent token + <tt>ps</tt></td>
<td>AS deployed</td>
<td>Federated</td>
<td>Full federation, AS policy enforcement</td>
</tr>

<tr>
<td>Agent token + <tt>ps</tt> + mission</td>
<td>Any or none</td>
<td>+ governance</td>
<td>Tool-call permissions, audit, PS-relayed interaction, consent-managed access</td>
</tr>
</tbody>
</table></section>
</section>

<section anchor="security-considerations"><name>Security Considerations</name>

<section anchor="proof-of-possession"><name>Proof-of-Possession</name>
<t>All AAuth tokens are proof-of-possession tokens. The holder must prove possession of the private key corresponding to the public key in the token's <tt>cnf</tt> claim.</t>
</section>

<section anchor="token-security"><name>Token Security</name>

<ul spacing="compact">
<li>Agent tokens bind agent keys to agent identity</li>
<li>Resource tokens bind access requests to resource identity, preventing confused deputy attacks</li>
<li>Auth tokens bind authorization grants to agent keys</li>
</ul>
</section>

<section anchor="pending-url-security"><name>Pending URL Security</name>

<ul spacing="compact">
<li>Pending URLs MUST be unguessable and SHOULD have limited lifetime</li>
<li>Pending URLs MUST be on the same origin as the server that issued them</li>
<li>Servers MUST verify the agent's identity on every poll</li>
<li>Once a terminal response is returned, the pending URL MUST return <tt>410 Gone</tt></li>
</ul>
</section>

<section anchor="clarification-chat-security"><name>Clarification Chat Security</name>

<ul spacing="compact">
<li>PSes MUST enforce a maximum number of clarification rounds</li>
<li>Clarification responses from agents are untrusted input and MUST be sanitized before display</li>
</ul>
</section>

<section anchor="untrusted-input"><name>Untrusted Input</name>
<t>All protocol inputs — JSON request bodies, clarification responses, justification strings, mission descriptions, and token claims — are untrusted input from potentially adversarial parties. This is consistent with standard web security practice where HTTP request bodies, headers, and query parameters are always treated as untrusted. Implementations MUST sanitize all values before rendering to users and MUST validate all values before processing. Markdown fields MUST be sanitized before rendering to prevent script injection.</t>
</section>

<section anchor="interaction-code-misdirection"><name>Interaction Code Misdirection</name>
<t>An attacker could attempt to trick a user into approving an authorization request by directing them to an interaction URL with the attacker's code. The PS mitigates this by displaying the full request context — the agent's identity, the resource being accessed, and the requested scope — so the user can recognize requests they did not initiate. A stronger mitigation is for the PS to interact directly with the user via a pre-established channel (push notification, email, or existing session) using <tt>requirement=approval</tt>, which eliminates the possibility of misdirection through attacker-supplied links entirely.</t>
</section>

<section anchor="as-discovery"><name>AS Discovery</name>
<t>The resource's AS is identified by the <tt>aud</tt> claim in the resource token. In three-party mode, <tt>aud</tt> identifies the PS; in four-party mode, it identifies the AS. Federation mechanics are described in <xref target="ps-as-federation"/>.</t>
</section>

<section anchor="aauth-access-security"><name>AAuth-Access Security</name>
<t>The <tt>AAuth-Access</tt> header carries an opaque wrapped token that is meaningful only to the issuing resource. The token MUST NOT be usable as a standalone bearer token — the resource wraps its internal authorization state so that the token is meaningless without a valid AAuth signature from the agent. The agent MUST include <tt>authorization</tt> in the signed components when presenting the token, binding it to the signed request.</t>
</section>

<section anchor="ps-as-auth-token-issuer"><name>PS as Auth Token Issuer</name>
<t>In three-party mode, the PS issues auth tokens directly without AS federation. The PS MUST protect its signing keys with the same rigor as an AS. Resources that accept PS-issued auth tokens are trusting the agent's PS — the trust basis differs from four-party mode where the resource trusts its own AS.</t>
</section>

<section anchor="agent-person-binding"><name>Agent-Person Binding</name>
<t>The PS MUST ensure that each agent is associated with exactly one person. This one-to-one binding is a trust invariant — it ensures that every action an agent takes is attributable to a single accountable party.</t>
<t>The binding is typically established when the person first authorizes the agent at the PS via the interaction flow. An organization administrator may pre-authorize agents for the organization. Once established, the PS MUST NOT allow a different person to claim the same agent. If an agent's association needs to change (e.g., an employee leaves an organization), the existing binding MUST be revoked and a new binding established.</t>
<t>This invariant enables:</t>

<ul spacing="compact">
<li><strong>Accountability</strong>: Every authorization decision traces to a single person.</li>
<li><strong>Consent integrity</strong>: Consent granted by one person cannot be exercised by a different person through the same agent.</li>
<li><strong>Audit</strong>: The PS can provide a complete record of an agent's actions on behalf of its person.</li>
<li><strong>Revocation</strong>: Revoking an agent's association with its person immediately prevents the agent from obtaining new auth tokens.</li>
</ul>
</section>

<section anchor="ps-as-high-value-target"><name>PS as High-Value Target</name>
<t>The PS is a centralized authority that sees every authorization in a mission. PS implementations MUST apply appropriate security controls including access control, audit logging, and monitoring. Compromise of a PS could affect all agents and missions it manages.</t>
<t>Several architectural properties mitigate this centralization risk. The person chooses their PS — no other party in the protocol imposes a PS, and the person can migrate to a different PS at any time. The PS MAY delegate authentication to an identity provider chosen by the person or organization (e.g., an enterprise IdP via OIDC federation), reducing the PS's role in credential management. The PS MAY also delegate policy evaluation to external services selected by the person, so that consent and authorization decisions are not solely determined by the PS operator. To the rest of the protocol, the PS presents a single interface regardless of how it is composed internally.</t>
</section>

<section anchor="call-chaining-identity"><name>Call Chaining Identity</name>
<t>When a resource acts as an agent in call chaining, it uses its own signing key and presents its own credentials. The resource MUST publish agent metadata so downstream parties can verify its identity.</t>
</section>

<section anchor="token-revocation-and-lifecycle"><name>Token Revocation and Lifecycle</name>
<t>Real-time revocation <xref target="token-revocation"/> and short token lifetimes provide layered access control. Organizations have multiple control points — agent server, PS, and AS — each of which can deny renewal or revoke tokens independently. Shorter auth token lifetimes reduce the window between a control action and natural expiration.</t>
</section>

<section anchor="tls-requirements"><name>TLS Requirements</name>
<t>All HTTPS connections MUST use TLS 1.2 or later, following the recommendations in BCP 195 <xref target="RFC9325"/>.</t>
</section>
</section>

<section anchor="privacy-considerations"><name>Privacy Considerations</name>

<section anchor="directed-identifiers"><name>Directed Identifiers</name>
<t>The PS SHOULD provide a pairwise pseudonymous user identifier (<tt>sub</tt>) per resource, preventing resources from correlating users across trust domains. Each resource sees a different <tt>sub</tt> for the same user, preserving user privacy.</t>
</section>

<section anchor="ps-visibility"><name>PS Visibility</name>
<t>In three-party and four-party modes, the PS sees every authorization request made by its agents — including the resource being accessed, the requested scope, and the mission context. This centralized visibility enables governance and audit, but it also means the PS is a sensitive data aggregation point. The person chooses to trust their PS with this visibility — no other party imposes the choice. PS implementations MUST apply appropriate access controls and data retention policies.</t>
<t>In two-party mode, no PS is involved and there is no centralized visibility — the resource handles authorization directly with the agent.</t>
</section>

<section anchor="mission-content-exposure"><name>Mission Content Exposure</name>
<t>The mission JSON is visible to the PS and, when included in resource tokens and auth tokens via the <tt>s256</tt> hash, its integrity is verifiable by any party that holds it. The approved mission JSON is shared between the agent and PS. Resources and ASes see only the <tt>s256</tt> hash and the approver URL, not the full mission content.</t>
</section>
</section>

<section anchor="iana-considerations"><name>IANA Considerations</name>

<section anchor="http-header-field-registration"><name>HTTP Header Field Registration</name>
<t>This specification registers the following HTTP header fields in the "Hypertext Transfer Protocol (HTTP) Field Name Registry" established by <xref target="RFC9110"/>:</t>

<ul>
<li>Header Field Name: <tt>AAuth-Requirement</tt></li>
<li>Status: permanent</li>
<li>Structured Type: Dictionary</li>
<li><t>Reference: This document, <xref target="requirement-responses"/></t>
</li>
<li><t>Header Field Name: <tt>AAuth-Access</tt></t>
</li>
<li><t>Status: permanent</t>
</li>
<li><t>Reference: This document, <xref target="aauth-access"/></t>
</li>
<li><t>Header Field Name: <tt>AAuth-Capabilities</tt></t>
</li>
<li><t>Status: permanent</t>
</li>
<li><t>Structured Type: List</t>
</li>
<li><t>Reference: This document, <xref target="aauth-capabilities"/></t>
</li>
<li><t>Header Field Name: <tt>AAuth-Mission</tt></t>
</li>
<li><t>Status: permanent</t>
</li>
<li><t>Structured Type: Dictionary</t>
</li>
<li><t>Reference: This document, <xref target="aauth-mission-request-header"/></t>
</li>
</ul>
</section>

<section anchor="http-authentication-scheme-registration"><name>HTTP Authentication Scheme Registration</name>
<t>This specification registers the following HTTP authentication scheme in the "Hypertext Transfer Protocol (HTTP) Authentication Scheme Registry" established by <xref target="RFC9110"/>:</t>

<ul spacing="compact">
<li>Authentication Scheme Name: <tt>AAuth</tt></li>
<li>Reference: This document, <xref target="aauth-access"/></li>
<li>Notes: Used with opaque access tokens returned via the <tt>AAuth-Access</tt> header. The token MUST be bound to an HTTP Message Signature — the <tt>authorization</tt> field MUST be included in the signature's covered components.</li>
</ul>
</section>

<section anchor="well-known-uri-registrations"><name>Well-Known URI Registrations</name>
<t>This specification registers the following well-known URIs per <xref target="RFC8615"/>:</t>
<table>
<thead>
<tr>
<th>URI Suffix</th>
<th>Change Controller</th>
<th>Reference</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>aauth-agent.json</tt></td>
<td>IETF</td>
<td>This document, <xref target="agent-server-metadata"/></td>
</tr>

<tr>
<td><tt>aauth-person.json</tt></td>
<td>IETF</td>
<td>This document, <xref target="ps-metadata"/></td>
</tr>

<tr>
<td><tt>aauth-access.json</tt></td>
<td>IETF</td>
<td>This document, <xref target="access-server-metadata"/></td>
</tr>

<tr>
<td><tt>aauth-resource.json</tt></td>
<td>IETF</td>
<td>This document, <xref target="resource-metadata"/></td>
</tr>
</tbody>
</table></section>

<section anchor="media-type-registrations"><name>Media Type Registrations</name>
<t>This specification registers the following media types:</t>

<section anchor="application-aa-agent-jwt"><name>application/aa-agent+jwt</name>

<ul spacing="compact">
<li>Type name: application</li>
<li>Subtype name: aa-agent+jwt</li>
<li>Required parameters: N/A</li>
<li>Optional parameters: N/A</li>
<li>Encoding considerations: binary; a JWT is a sequence of Base64url-encoded parts separated by period characters</li>
<li>Security considerations: See <xref target="security-considerations"/></li>
<li>Interoperability considerations: N/A</li>
<li>Published specification: This document, <xref target="agent-tokens"/></li>
<li>Applications that use this media type: AAuth agents, PSes, and ASes</li>
<li>Fragment identifier considerations: N/A</li>
</ul>
</section>

<section anchor="application-aa-auth-jwt"><name>application/aa-auth+jwt</name>

<ul spacing="compact">
<li>Type name: application</li>
<li>Subtype name: aa-auth+jwt</li>
<li>Required parameters: N/A</li>
<li>Optional parameters: N/A</li>
<li>Encoding considerations: binary; a JWT is a sequence of Base64url-encoded parts separated by period characters</li>
<li>Security considerations: See <xref target="security-considerations"/></li>
<li>Interoperability considerations: N/A</li>
<li>Published specification: This document, <xref target="auth-tokens"/></li>
<li>Applications that use this media type: AAuth ASes, agents, and resources</li>
<li>Fragment identifier considerations: N/A</li>
</ul>
</section>

<section anchor="application-aa-resource-jwt"><name>application/aa-resource+jwt</name>

<ul spacing="compact">
<li>Type name: application</li>
<li>Subtype name: aa-resource+jwt</li>
<li>Required parameters: N/A</li>
<li>Optional parameters: N/A</li>
<li>Encoding considerations: binary; a JWT is a sequence of Base64url-encoded parts separated by period characters</li>
<li>Security considerations: See <xref target="security-considerations"/></li>
<li>Interoperability considerations: N/A</li>
<li>Published specification: This document, <xref target="resource-tokens"/></li>
<li>Applications that use this media type: AAuth resources and ASes</li>
<li>Fragment identifier considerations: N/A</li>
</ul>
</section>
</section>

<section anchor="jwt-type-registrations"><name>JWT Type Registrations</name>
<t>This specification registers the following JWT <tt>typ</tt> header parameter values in the "JSON Web Token Types" sub-registry:</t>
<table>
<thead>
<tr>
<th>Type Value</th>
<th>Reference</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>aa-agent+jwt</tt></td>
<td>This document, <xref target="agent-tokens"/></td>
</tr>

<tr>
<td><tt>aa-auth+jwt</tt></td>
<td>This document, <xref target="auth-tokens"/></td>
</tr>

<tr>
<td><tt>aa-resource+jwt</tt></td>
<td>This document, <xref target="resource-tokens"/></td>
</tr>
</tbody>
</table></section>

<section anchor="jwt-claims-registrations"><name>JWT Claims Registrations</name>
<t>This specification registers the following claims in the IANA "JSON Web Token Claims" registry established by <xref target="RFC7519"/>:</t>
<table>
<thead>
<tr>
<th>Claim Name</th>
<th>Claim Description</th>
<th>Change Controller</th>
<th>Reference</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>dwk</tt></td>
<td>Discovery Well-Known document name</td>
<td>IETF</td>
<td>This document</td>
</tr>

<tr>
<td><tt>ps</tt></td>
<td>Person Server URL</td>
<td>IETF</td>
<td>This document</td>
</tr>

<tr>
<td><tt>agent</tt></td>
<td>Agent identifier</td>
<td>IETF</td>
<td>This document</td>
</tr>

<tr>
<td><tt>agent_jkt</tt></td>
<td>JWK Thumbprint of the agent's signing key</td>
<td>IETF</td>
<td>This document</td>
</tr>

<tr>
<td><tt>mission</tt></td>
<td>Mission object (approver, s256) in resource tokens and auth tokens</td>
<td>IETF</td>
<td>This document</td>
</tr>
</tbody>
</table></section>

<section anchor="aauth-requirement-value-registry"><name>AAuth Requirement Value Registry</name>
<t>This specification establishes the AAuth Requirement Value Registry. The registry policy is Specification Required (<xref target="RFC8126"/>).</t>
<table>
<thead>
<tr>
<th>Value</th>
<th>Reference</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>interaction</tt></td>
<td>This document</td>
</tr>

<tr>
<td><tt>approval</tt></td>
<td>This document</td>
</tr>

<tr>
<td><tt>auth-token</tt></td>
<td>This document</td>
</tr>

<tr>
<td><tt>clarification</tt></td>
<td>This document</td>
</tr>

<tr>
<td><tt>claims</tt></td>
<td>This document</td>
</tr>
</tbody>
</table></section>

<section anchor="aauth-capability-value-registry"><name>AAuth Capability Value Registry</name>
<t>This specification establishes the AAuth Capability Value Registry. The registry policy is Specification Required (<xref target="RFC8126"/>).</t>
<table>
<thead>
<tr>
<th>Value</th>
<th>Reference</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>interaction</tt></td>
<td>This document</td>
</tr>

<tr>
<td><tt>clarification</tt></td>
<td>This document</td>
</tr>

<tr>
<td><tt>payment</tt></td>
<td>This document</td>
</tr>
</tbody>
</table></section>

<section anchor="uri-scheme-registration"><name>URI Scheme Registration</name>
<t>This specification registers the <tt>aauth</tt> URI scheme in the "Uniform Resource Identifier (URI) Schemes" registry (<xref target="RFC7595"/>):</t>

<ul spacing="compact">
<li>Scheme name: <tt>aauth</tt></li>
<li>Status: Permanent</li>
<li>Applications/protocols that use this scheme: AAuth Protocol</li>
<li>Contact: IETF</li>
<li>Change controller: IETF</li>
<li>Reference: This document, <xref target="agent-identifiers"/></li>
</ul>
<t>The <tt>aauth</tt> URI scheme follows the pattern established by the <tt>acct</tt> scheme (<xref target="RFC7565"/>). An <tt>aauth</tt> URI identifies an agent instance and has the syntax <tt>aauth:local@domain</tt>, where <tt>local</tt> is the agent-specific part and <tt>domain</tt> is the agent server's domain name. The <tt>aauth</tt> URI is used in the <tt>sub</tt> claim of agent tokens, the <tt>agent</tt> field of resource tokens and mission objects, and the <tt>act.sub</tt> claim of auth tokens.</t>
</section>
</section>

<section anchor="implementation-status"><name>Implementation Status</name>
<t><em>Note: This section is to be removed before publishing as an RFC.</em></t>
<t>This section records the status of known implementations of the protocol defined by this specification at the time of posting of this Internet-Draft, and is based on a proposal described in <xref target="RFC7942"/>. The description of implementations in this section is intended to assist the IETF in its decision processes in progressing drafts to RFCs.</t>
<t>The following implementations are known:</t>

<ul spacing="compact">
<li><strong>TypeScript</strong> — <eref target="https://github.com/hellocoop/AAuth">github.com/hellocoop/AAuth</eref>. Organization: Hellō. Coverage: agent token issuance, HTTP Message Signatures, resource token exchange, PS token endpoint. Level of maturity: exploratory.</li>
<li><strong>Python</strong> — <eref target="https://github.com/christian-posta/aauth-full-demo">github.com/christian-posta/aauth-full-demo</eref>. Contact: Christian Posta. Coverage: agent-to-resource flows with Keycloak as AS. Level of maturity: exploratory.</li>
<li><strong>Java (Keycloak SPI)</strong> — <eref target="https://github.com/christian-posta/keycloak-aauth-extension">github.com/christian-posta/keycloak-aauth-extension</eref>. Contact: Christian Posta. Coverage: AAuth access server extension for Keycloak 26.2.5. Level of maturity: exploratory.</li>
</ul>
</section>

<section anchor="document-history"><name>Document History</name>
<t><em>Note: This section is to be removed before publishing as an RFC.</em></t>

<ul>
<li><t>draft-hardt-aauth-protocol-01</t>

<ul spacing="compact">
<li>Complete rework of specification</li>
</ul></li>
<li><t>draft-hardt-aauth-protocol-00</t>

<ul spacing="compact">
<li>Initial submission</li>
</ul></li>
</ul>
</section>

<section anchor="acknowledgments"><name>Acknowledgments</name>
<t>The author would like to thank reviewers for their feedback on concepts and earlier drafts: Aaron Pareki, Christian Posta, Frederik Krogsdal Jacobsen, Jared Hanson, Karl McGuinness, Nate Barbettini, Wils Dawson.</t>
</section>

</middle>

<back>
<references><name>References</name>
<references><name>Normative References</name>
<reference anchor="I-D.hardt-httpbis-signature-key" target="https://dickhardt.github.io/signature-key/draft-hardt-httpbis-signature-key.html">
  <front>
    <title>HTTP Signature Keys</title>
    <author fullname="Dick Hardt" initials="D." surname="Hardt">
      <organization>Hellō</organization>
    </author>
    <author fullname="Thibault Meunier" initials="T." surname="Meunier">
      <organization>Cloudflare</organization>
    </author>
    <date year="2026"/>
  </front>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ryan-httpauth-payment.xml"/>
<reference anchor="OpenID.Core" target="https://openid.net/specs/openid-connect-core-1_0.html">
  <front>
    <title>OpenID Connect Core 1.0</title>
    <author fullname="Nat Sakimura" initials="N." surname="Sakimura">
      <organization>NRI</organization>
    </author>
    <author fullname="John Bradley" initials="J." surname="Bradley">
      <organization>Ping Identity</organization>
    </author>
    <author fullname="Michael B. Jones" initials="M." surname="Jones">
      <organization>Microsoft</organization>
    </author>
    <author fullname="Breno de Medeiros" initials="B." surname="de Medeiros">
      <organization>Google</organization>
    </author>
    <author fullname="Chuck Mortimore" initials="C." surname="Mortimore">
      <organization>Salesforce</organization>
    </author>
    <date year="2014" month="November"/>
  </front>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5890.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6749.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6979.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7240.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7515.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7517.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7519.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7595.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7638.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7800.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8032.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8126.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8259.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8615.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8693.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8941.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9068.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9110.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9325.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9421.xml"/>
</references>
<references><name>Informative References</name>
<reference anchor="CommonMark" target="https://spec.commonmark.org/0.31.2/">
  <front>
    <title>CommonMark Spec</title>
    <author fullname="John MacFarlane" initials="J." surname="MacFarlane"/>
    <date year="2024"/>
  </front>
</reference>
<reference anchor="OpenID.Enterprise" target="https://openid.net/specs/openid-connect-enterprise-extensions-1_0.html">
  <front>
    <title>OpenID Connect Enterprise Extensions 1.0</title>
    <author fullname="Dick Hardt" initials="D." surname="Hardt">
      <organization>Hellō</organization>
    </author>
    <author fullname="Karl McGuinness" initials="K." surname="McGuinness">
      <organization>Okta</organization>
    </author>
    <date year="2025"/>
  </front>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5905.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7518.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7565.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7591.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7636.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7942.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8414.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8628.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9449.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9530.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9635.xml"/>
<reference anchor="x402" target="https://docs.x402.org">
  <front>
    <title>x402: HTTP 402 Payment Protocol</title>
    <author>
      <organization>x402 Foundation</organization>
    </author>
    <date year="2025"/>
  </front>
</reference>
</references>
</references>

<section anchor="agent-token-acquisition"><name>Agent Token Acquisition Patterns</name>
<t>This appendix describes common patterns for how agents obtain agent tokens from their agent server. In all patterns, the agent generates a signing key pair, proves its identity to the agent server, and receives an agent token binding the key to an agent identifier. Each pattern differs in how the agent proves its identity and what trust assumption the agent server relies on.</t>

<section anchor="self-hosted-agents"><name>Self-Hosted Agents</name>
<t>A user publishes agent metadata and a JWKS at a domain they control (e.g., <tt>username.github.io/.well-known/aauth-agent.json</tt>) — no active server is required, only static files. The agent's public key is included in the published JWKS. The corresponding private key is held on the user's machine — potentially in a secure enclave or hardware token. The agent creates its own agent token, signed by the private key. Verifiers resolve the agent token against the published JWKS.</t>
<t>This is the simplest deployment model — a developer or user publishes static files and runs software that signs its own requests. When the agent calls a new resource for the first time, the resource can verify the agent's identity from the published metadata and kick off registration, account creation, or consent — all without any prior relationship.</t>
<t><strong>Trust assumption:</strong> The trust anchor is the published JWKS and the private key held by the user. No server-side logic is involved — verification relies entirely on the static metadata and key material.</t>
</section>

<section anchor="user-login"><name>User Login</name>

<ol spacing="compact">
<li>The agent opens a browser and redirects the user to the agent server's web interface.</li>
<li>The user authenticates at the agent server.</li>
<li>The agent generates an ephemeral signing key pair, stores the private key in a platform vault (macOS Keychain, Windows TPM, Linux Secret Service, iOS Secure Enclave, Android Keystore), and sends the public key to the agent server.</li>
<li>The agent server issues an agent token binding the ephemeral key to an agent identifier and returns it to the agent (e.g., via localhost callback or app redirect).</li>
</ol>
<t>This pattern applies to desktop apps, CLI tools, mobile apps, and browser-based apps — any context where a user can authenticate interactively.</t>
<t>The agent may also hold a stable key in hardware (TPM, secure enclave) or a platform keychain. During the initial user login flow, the agent server records the stable public key alongside the agent identity. When the agent token expires, the agent can renew it by sending its new ephemeral public key in a <tt>scheme=jkt-jwt</tt> request signed by the stable key, without requiring the user to log in again.</t>
<t><strong>Trust assumption:</strong> The agent server trusts the user's authentication but cannot verify which software is running — only that the user authorized the agent. For renewal via stable key, the agent server trusts that the key registered at enrollment continues to represent the same agent.</t>
</section>

<section anchor="desktop-and-cli-applications"><name>Desktop and CLI Applications</name>
<t>Desktop platforms generally do not provide application-level attestation comparable to mobile platforms. The user login pattern above is the most common approach. The agent stores its key in a platform vault (macOS Keychain, Windows TPM, Linux Secret Service).</t>
</section>

<section anchor="mobile-applications"><name>Mobile Applications</name>

<ol spacing="compact">
<li>The app generates an ephemeral signing key pair, optionally backed by the device's secure enclave (iOS Secure Enclave, Android StrongBox).</li>
<li>The app obtains a platform attestation — iOS App Attest assertion or Android Play Integrity verdict — binding the app identity and the ephemeral public key.</li>
<li>The app sends the attestation and public key to the agent server.</li>
<li>The agent server verifies the attestation against Apple's or Google's attestation service and issues an agent token.</li>
</ol>
<t>The platform attestation proves the app is a genuine installation from the app store, running on a real device, and has not been tampered with. If the key is hardware-backed, the attestation also proves the key cannot be exported. Mobile apps MAY also use the user login pattern when platform attestation is not available.</t>
<t><strong>Trust assumption:</strong> The agent server trusts the platform's attestation that the app is a genuine, untampered installation running on a real device.</t>
</section>

<section anchor="browser-based-applications"><name>Browser-Based Applications</name>

<ol spacing="compact">
<li>The web server — which acts as the agent server — authenticates the user. The recommended mechanism is WebAuthn, which binds authentication to the device and origin, preventing scripts or headless browsers from impersonating the web page to obtain an agent token.</li>
<li>The web app generates an ephemeral signing key pair using the Web Crypto API (non-extractable if supported) and sends it to the web server.</li>
<li>The web server issues an agent token binding the web app's ephemeral public key to an agent identifier and returns it.</li>
</ol>
<t>The key pair and agent token exist only for the lifetime of the browser session. The web server controls both the agent identity and the issuance.</t>
<t><strong>Trust assumption:</strong> The web server is the agent server and controls the entire lifecycle. The agent token lifetime is tied to the browser session. When WebAuthn is used, authentication is bound to the device and origin rather than relying solely on session credentials.</t>
</section>

<section anchor="server-workloads"><name>Server Workloads</name>

<ol spacing="compact">
<li>The agent generates an ephemeral signing key pair (e.g., Ed25519).</li>
<li>The agent obtains a platform attestation from its runtime environment — such as a SPIFFE SVID from a SPIRE agent, a WIMSE workload identity token, or a cloud provider instance identity document (AWS IMDSv2, GCP metadata, Azure IMDS).</li>
<li>The agent presents the attestation and its ephemeral public key to the agent server.</li>
<li>The agent server verifies the attestation against the platform's trust root and issues an agent token with the ephemeral key in the <tt>cnf</tt> claim.</li>
</ol>
<t>On managed infrastructure, the platform may additionally attest the software identity (container image hash, binary signature) alongside the workload identity, allowing the agent server to restrict tokens to known software.</t>
<t><strong>Trust assumption:</strong> The agent server trusts the platform's attestation that the workload is what it claims to be.</t>
</section>

<section anchor="managed-desktops"><name>Managed Desktops</name>
<t>On managed desktops (e.g., corporate MDM-enrolled devices), the management platform may provide device and software attestation similar to server workloads. The agent presents the platform attestation alongside its ephemeral key, and the agent server verifies the device is managed and the software is approved.</t>
<t><strong>Trust assumption:</strong> The agent server trusts the management platform's attestation that the device is managed and the software is approved.</t>
</section>
</section>

<section anchor="detailed-flows"><name>Detailed Flows</name>
<t>This appendix provides complete end-to-end flows for each adoption mode.</t>

<section anchor="two-party-resource-managed-with-interaction"><name>Two-Party: Resource-Managed with Interaction</name>
<t>The agent calls a resource that requires user interaction for authorization. The resource returns a deferred response, the user completes interaction, and the agent receives an AAuth-Access token for subsequent calls.</t>

<sourcecode type="ascii-art"><![CDATA[Agent                            Resource              User
  |                                 |                    |
  | HTTPSig w/ agent token          |                    |
  |-------------------------------->|                    |
  |                                 |                    |
  | 202 Accepted                    |                    |
  | AAuth-Requirement:              |                    |
  |   requirement=interaction;      |                    |
  |   url=...; code=...            |                    |
  | Location: /pending/abc          |                    |
  |<--------------------------------|                    |
  |                                 |                    |
  | direct user to {url}?code={code}|                    |
  |                                 |                    |
  |                                 | authenticate       |
  |                                 | and consent        |
  |                                 |<------------------>|
  |                                 |                    |
  | GET /pending/abc                |                    |
  |-------------------------------->|                    |
  |                                 |                    |
  | 200 OK                          |                    |
  | AAuth-Access: opaque-token      |                    |
  |<--------------------------------|                    |
  |                                 |                    |
  | HTTPSig w/ agent token          |                    |
  | Authorization: AAuth opaque-tok |                    |
  |-------------------------------->|                    |
  |                                 |                    |
  | 200 OK                          |                    |
  |<--------------------------------|                    |
]]>
</sourcecode>
</section>

<section anchor="four-party-401-resource-challenge"><name>Four-Party: 401 Resource Challenge</name>
<t>A machine-to-machine agent calls a resource directly. The resource challenges with a <tt>401</tt> containing a resource token. The PS federates with the AS without user interaction.</t>

<sourcecode type="ascii-art"><![CDATA[Agent                          Resource               PS
  |                               |                    |
  | HTTPSig w/ agent token        |                    |
  | AAuth-Mission                 |                    |
  |------------------------------>|                    |
  |                               |                    |
  | 401 + resource_token          |                    |
  |<------------------------------|                    |
  |                               |                    |
  | HTTPSig w/ agent token        |                    |
  | POST token_endpoint           |                    |
  | w/ resource_token             |                    |
  |----------------------------------------------->|
  |                               |                    |
  |                               | [PS federates     |
  |                               |  with AS]         |
  |                               |                    |
  | auth_token                    |                    |
  |<-----------------------------------------------|
  |                               |                    |
  | HTTPSig w/ auth token         |                    |
  |------------------------------>|                    |
  |                               |                    |
  | 200 OK                        |                    |
  |<------------------------------|                    |
]]>
</sourcecode>
</section>

<section anchor="four-party-user-authorization"><name>Four-Party: User Authorization</name>
<t>The agent obtains a resource token from the resource's <tt>authorization_endpoint</tt>, then requests authorization from the PS. The PS requires user consent via interaction.</t>

<sourcecode type="ascii-art"><![CDATA[User        Agent                Resource             PS
  |           |                     |                  |
  |           | HTTPSig w/ agent token                 |
  |           | POST authorize_ep   |                  |
  |           |-------------------->|                  |
  |           |                     |                  |
  |           | resource_token      |                  |
  |           |<--------------------|                  |
  |           |                     |                  |
  |           | HTTPSig w/ agent token                 |
  |           | POST token_endpoint |                  |
  |           | w/ resource_token   |                  |
  |           |----------------------------------->|
  |           |                     |                  |
  |           | 202 Accepted        |                  |
  |           | requirement=interaction                |
  |           | code="ABCD1234"     |                  |
  |           |<-----------------------------------|
  |           |                     |                  |
  | direct to |                     |                  |
  | {url}?code={code}              |                  |
  |<----------|                     |                  |
  |           |                     |                  |
  | authenticate and consent        |                  |
  |-------------------------------------------------->|
  |           |                     |                  |
  | redirect to callback_url       |                  |
  |<--------------------------------------------------|
  |           |                     |                  |
  | callback  |                     |                  |
  |---------->|                     |                  |
  |           |                     |                  |
  |           | GET /pending/abc    |                  |
  |           |----------------------------------->|
  |           |                     |                  |
  |           | 200 OK, auth_token  |                  |
  |           |<-----------------------------------|
  |           |                     |                  |
  |           | HTTPSig w/ auth token                  |
  |           |-------------------->|                  |
  |           |                     |                  |
  |           | 200 OK              |                  |
  |           |<--------------------|                  |
]]>
</sourcecode>
</section>

<section anchor="four-party-direct-approval"><name>Four-Party: Direct Approval</name>
<t>The PS obtains approval directly — via push notification, existing session, or email — without the agent facilitating a redirect.</t>

<sourcecode type="ascii-art"><![CDATA[Agent                 Resource       PS              User
  |                      |            |                |
  | HTTPSig w/ agent token            |                |
  | POST authorize_ep    |            |                |
  |--------------------->|            |                |
  |                      |            |                |
  | resource_token       |            |                |
  |<---------------------|            |                |
  |                      |            |                |
  | HTTPSig w/ agent token            |                |
  | POST token_endpoint  |            |                |
  | w/ resource_token    |            |                |
  |----------------------------------->|                |
  |                      |            |                |
  | 202 Accepted         |            |                |
  | requirement=approval |            |                |
  |<-----------------------------------|                |
  |                      |            |                |
  |                      |            | push / email   |
  |                      |            |--------------->|
  |                      |            |                |
  |                      |            | approve        |
  |                      |            |<---------------|
  |                      |            |                |
  | GET /pending/jkl     |            |                |
  |----------------------------------->|                |
  |                      |            |                |
  | 200 OK, auth_token   |            |                |
  |<-----------------------------------|                |
  |                      |            |                |
  | HTTPSig w/ auth token|            |                |
  |--------------------->|            |                |
  |                      |            |                |
  | 200 OK               |            |                |
  |<---------------------|            |                |
]]>
</sourcecode>
</section>

<section anchor="four-party-call-chaining"><name>Four-Party: Call Chaining</name>
<t>See <xref target="call-chaining"/> for normative requirements. Resource 1 acts as an agent, sending the downstream resource token plus its own agent token and the upstream auth token to the PS.</t>

<sourcecode type="ascii-art"><![CDATA[Agent        Resource 1       Resource 2          PS
  |              |                |                 |
  | HTTPSig w/   |                |                 |
  | auth token   |                |                 |
  |------------->|                |                 |
  |              |                |                 |
  |              | HTTPSig w/     |                 |
  |              | R1 agent token |                 |
  |              | AAuth-Mission  |                 |
  |              |--------------->|                 |
  |              |                |                 |
  |              | 401            |                 |
  |              | + resource_tok |                 |
  |              |<---------------|                 |
  |              |                |                 |
  |              | POST token_endpoint              |
  |              | resource_token from R2           |
  |              | upstream_token                   |
  |              | agent_token (R1's)               |
  |              |------------------------------>|
  |              |                |                 |
  |              |                | [PS federates   |
  |              |                |  with R2's AS]  |
  |              |                |                 |
  |              | auth_token for R2                |
  |              |<------------------------------|
  |              |                |                 |
  |              | HTTPSig w/     |                 |
  |              | auth token     |                 |
  |              |--------------->|                 |
  |              |                |                 |
  |              | 200 OK         |                 |
  |              |<---------------|                 |
  |              |                |                 |
  | 200 OK       |                |                 |
  |<-------------|                |                 |
]]>
</sourcecode>
</section>

<section anchor="interaction-chaining-1"><name>Interaction Chaining</name>
<t>See <xref target="interaction-chaining"/> for normative requirements. When the PS requires user interaction for the downstream access, Resource 1 chains the interaction back to the original agent.</t>

<sourcecode type="ascii-art"><![CDATA[User      Agent       Resource 1      Resource 2    PS
  |         |              |               |          |
  |         | HTTPSig req  |               |          |
  |         |------------->|               |          |
  |         |              |               |          |
  |         |              | HTTPSig req   |          |
  |         |              | (as agent)    |          |
  |         |              | AAuth-Mission |          |
  |         |              |-------------->|          |
  |         |              |               |          |
  |         |              | 401           |          |
  |         |              | + resource_tok|          |
  |         |              |<--------------|          |
  |         |              |               |          |
  |         |              | POST token_ep |          |
  |         |              | resource_tok, |          |
  |         |              | upstream_tok, |          |
  |         |              | agent_tok     |          |
  |         |              |------------------------->|
  |         |              |               |          |
  |         |              | 202 Accepted  |          |
  |         |              | interaction   |          |
  |         |              |<-------------------------|
  |         |              |               |          |
  |         | 202 Accepted |               |          |
  |         | interaction  |               |          |
  |         | code="MNOP"  |               |          |
  |         |<-------------|               |          |
  |         |              |               |          |
  | direct to R1 {url}    |               |          |
  |<--------|              |               |          |
  |         |              |               |          |
  | R1 redirects to PS    |               |          |
  |----------------------->|               |          |
  | PS {url}?code={code}  |               |          |
  |<-----------------------|               |          |
  |         |              |               |          |
  | authenticate and consent               |          |
  |---------------------------------------------->|
  |         |              |               |          |
  | redirect to R1 callback               |          |
  |<----------------------------------------------|
  |         |              |               |          |
  |         |         [R1 polls PS,        |          |
  |         |          gets auth_token]    |          |
  |         |              |               |          |
  |         |              | HTTPSig w/    |          |
  |         |              | auth token    |          |
  |         |              |-------------->|          |
  |         |              |               |          |
  |         |              | 200 OK        |          |
  |         |              |<--------------|          |
  |         |              |               |          |
  | redirect to agent callback             |          |
  |<-----------------------|               |          |
  |         |              |               |          |
  | callback|              |               |          |
  |-------->|              |               |          |
  |         |              |               |          |
  |         | GET /pending |               |          |
  |         |------------->|               |          |
  |         |              |               |          |
  |         | 200 OK       |               |          |
  |         |<-------------|               |          |
]]>
</sourcecode>
</section>
</section>

<section anchor="design-rationale"><name>Design Rationale</name>

<section anchor="identity-and-foundation"><name>Identity and Foundation</name>

<section anchor="why-https-based-agent-identity"><name>Why HTTPS-Based Agent Identity</name>
<t>HTTPS URLs as agent identifiers enable dynamic ecosystems without pre-registration.</t>
</section>

<section anchor="why-per-instance-agent-identity"><name>Why Per-Instance Agent Identity</name>
<t>OAuth's <tt>client_id</tt> identifies an application — every instance of the same app shares a single identifier and typically a single set of credentials. AAuth's <tt>aauth:local@domain</tt> agent identifier identifies a specific instance with its own signing key. This enables per-instance authorization (grant access to this specific agent process, not all instances of the app), per-instance revocation (revoke one compromised instance without affecting others), and per-instance audit (trace every action to the specific instance that performed it). The agent server controls which instances receive agent tokens, providing centralized governance over a distributed agent fleet.</t>
</section>

<section anchor="why-every-agent-has-a-person"><name>Why Every Agent Has a Person</name>
<t>Every agent acts on behalf of a person — the entity accountable for the agent's actions. AAuth enables a person server to maintain this link, making it visible and enforceable across the protocol. When present, the PS ensures there is always an accountable party for authorization decisions, audit, and liability.</t>
</section>

<section anchor="why-the-ps-claim-in-agent-tokens"><name>Why the <tt>ps</tt> Claim in Agent Tokens</name>
<t>Resources need to discover the agent's PS to issue resource tokens in three-party mode. The <tt>ps</tt> claim in the agent token provides this discovery without requiring the <tt>AAuth-Mission</tt> header, which is only present when the agent is operating within a mission. This separates PS discovery from mission governance — an agent can use three-party mode without missions.</t>
</section>
</section>

<section anchor="protocol-mechanics"><name>Protocol Mechanics</name>

<section anchor="why-json-in-well-known-uris"><name>Why <tt>.json</tt> in Well-Known URIs</name>
<t>AAuth well-known metadata URIs use the <tt>.json</tt> extension (e.g., <tt>/.well-known/aauth-agent.json</tt>) rather than the extensionless convention used by OAuth and OpenID Connect. The <tt>.json</tt> extension makes the content type immediately obvious — no content negotiation is needed. More importantly, it enables static file hosting: a <tt>.json</tt> file served from GitHub Pages, S3, or a CDN works without server-side configuration. This aligns with AAuth's self-hosted agent model <xref target="agent-token-acquisition"/>, where an agent's metadata can be published as static files with no active server.</t>
</section>

<section anchor="why-standard-http-async-pattern"><name>Why Standard HTTP Async Pattern</name>
<t>AAuth uses standard HTTP async semantics (<tt>202 Accepted</tt>, <tt>Location</tt>, <tt>Prefer: wait</tt>, <tt>Retry-After</tt>). This applies uniformly to all endpoints, aligns with RFC 7240, replaces OAuth device flow, supports headless agents, and enables clarification chat.</t>
</section>

<section anchor="why-json-instead-of-form-encoded"><name>Why JSON Instead of Form-Encoded</name>
<t>JSON is the standard format for modern APIs. AAuth uses JSON for both request and response bodies.</t>
</section>

<section anchor="why-no-authorization-code"><name>Why No Authorization Code</name>
<t>AAuth eliminates authorization codes entirely. OAuth authorization codes require PKCE (<xref target="RFC7636"/>) to prevent interception attacks, adding complexity for both clients and servers. AAuth avoids the problem: the user redirect carries only the callback URL, which has no security value to an attacker. The auth token is delivered exclusively via polling, authenticated by the agent's HTTP Message Signature.</t>
</section>

<section anchor="why-callback-url-has-no-security-role"><name>Why Callback URL Has No Security Role</name>
<t>Tokens never pass through the user's browser. The callback URL is purely a UX optimization.</t>
</section>

<section anchor="why-no-refresh-token"><name>Why No Refresh Token</name>
<t>AAuth has no refresh tokens. When an auth token expires, the agent obtains a fresh resource token and submits it through the standard authorization flow. This gives the resource a voice in every re-authorization — the resource can adjust scope, require step-up authorization, or deny access based on current policy. A separate refresh token would bypass the resource entirely, and is unnecessary given that the standard flow is a single additional request.</t>
</section>

<section anchor="why-reuse-openid-connect-vocabulary"><name>Why Reuse OpenID Connect Vocabulary</name>
<t>AAuth reuses OpenID Connect scope values, identity claims, and enterprise parameters. This lowers the adoption barrier.</t>
</section>
</section>

<section anchor="architecture"><name>Architecture</name>

<section anchor="why-a-separate-person-server"><name>Why a Separate Person Server</name>
<t>The PS is distinct from the AS because they serve different parties with different concerns. The PS represents the agent and its user — it handles consent, identity, mission governance, and audit. The AS represents the resource — it evaluates policy and issues tokens. Combining these into a single entity would conflate the interests of the requesting party with the interests of the resource owner, which is the same conflation that makes OAuth insufficient for cross-domain agent ecosystems.</t>
</section>

<section anchor="why-four-adoption-modes"><name>Why Four Adoption Modes</name>
<t>The protocol supports identity-based, resource-managed (two-party), PS-managed (three-party), and federated (four-party) resource access modes, with agent governance as an orthogonal layer. A resource that only verifies agent signatures can start using AAuth today without deploying a PS or AS. As the ecosystem matures, the same resource can issue resource tokens to the agent's PS (three-party) and eventually deploy its own AS (four-party). Each mode is self-contained and useful — not a stepping stone to the "real" protocol. Agent governance (missions, permissions, audit) works independently of resource access modes.</t>
</section>

<section anchor="why-resource-tokens"><name>Why Resource Tokens</name>
<t>In GNAP and OAuth, the resource server is a passive consumer of tokens — it verifies them but never produces signed artifacts. AAuth inverts this: the resource cryptographically asserts what is being requested by issuing a resource token that binds the resource's own identity, the agent's key thumbprint, the requested scope, and the mission context into a single signed JWT. This prevents confused deputy attacks — an attacker cannot substitute a different resource in the authorization flow because the resource token is signed by the resource. It also gives the resource a voice in every authorization and re-authorization, and provides a complete audit artifact linking the request to a specific resource, agent, scope, and mission.</t>
</section>

<section anchor="why-opaque-aauth-access-tokens"><name>Why Opaque AAuth-Access Tokens</name>
<t>In two-party mode, the resource returns an opaque wrapped token via the <tt>AAuth-Access</tt> header rather than a JWT auth token. This allows the resource to wrap its existing authorization infrastructure (OAuth access tokens, session tokens, etc.) without exposing internal structure. The token is bound to the AAuth signature — the agent includes it in the <tt>Authorization</tt> header as a covered component — so it cannot be stolen and replayed as a standalone bearer token.</t>
</section>

<section anchor="why-missions-are-not-a-policy-language"><name>Why Missions Are Not a Policy Language</name>
<t>Missions are intentionally not a machine-evaluable policy language. AAuth separates two kinds of authorization decisions:</t>

<ul>
<li><t><strong>Deterministic policy</strong> is handled by scopes, resource tokens, and AS policy evaluation. These are mechanically evaluable — "does this agent have <tt>data.read</tt> scope for this resource?" A policy engine (Cedar, OPA/Rego, or any other) can answer this question consistently and automatically.</t>
</li>
<li><t><strong>Contextual governance</strong> is handled by missions, justifications, and clarification at the PS. These are the contextual decisions that policy engines cannot answer — "is booking a $10,000 flight reasonable for planning a weekend trip?" or "should this agent access the HR database given what it's trying to accomplish?" The mission description, the agent's justification for each resource access, and the clarification dialog between user and agent provide the context for these decisions.</t>
</li>
</ul>
<t>Prior attempts to make authorization semantics machine-evaluable across domains have not scaled. OAuth Rich Authorization Requests (RAR) require clients and servers to agree on domain-specific <tt>type</tt> values and JSON structures — workable within a single API but combinatorially explosive across arbitrary services. UMA attempted cross-domain resource sharing with machine-readable permission tickets, but adoption stalled because resource owners, requesting parties, and authorization servers could not converge on shared semantics for what permissions meant across organizational boundaries. The fundamental problem is that the meaning of "appropriate access" is contextual, evolving, and domain-specific — it cannot be captured in a predefined vocabulary that all parties share.</t>
<t>Missions solve this differently. Rather than requiring all parties to agree on machine-evaluable semantics, AAuth concentrates governance evaluation at the PS — the only party with full context. The PS has the mission description, the user's identity and organizational context, the agent's justification for each request, the history of what the agent has done so far, and a channel to the user for clarification. No other party in the protocol has this context, and no predefined policy language can substitute for it.</t>
<t>This context can be presented to humans or to agents acting as decision-makers. The PS does not need to evaluate missions deterministically — it presents the mission context, the justification, and the resource request to whatever decision-maker is appropriate: a human reviewing a consent screen, an AI agent evaluating policy on behalf of an organization, or an automated system applying heuristics. As AI decision-making matures, governance can shift from human review to agent evaluation — without changing the protocol. AAuth standardizes how context is conveyed to the decision-maker; it does not prescribe how the decision is made.</t>
<t>The mission's <tt>description</tt> is Markdown because it represents human intent, not machine policy. The <tt>approved_tools</tt> array provides structured machine-evaluable elements where appropriate. Resources and access servers do not need the mission content — they enforce their own deterministic policies independently. The mission is a further restriction applied by the PS, and only the PS has sufficient context to evaluate it. Distributing mission semantics to other parties would be both a privacy leak and a false promise of enforcement, since those parties lack the context to evaluate the mission meaningfully.</t>
</section>

<section anchor="why-missions-have-only-two-states"><name>Why Missions Have Only Two States</name>
<t>Missions are either <strong>active</strong> or <strong>terminated</strong>. There is no suspended state. A suspended state would require the agent to learn that the mission has resumed, but AAuth has no push channel from the PS to the agent — the agent can only poll. For short pauses (minutes), the deferred response mechanism already provides natural waiting via <tt>202</tt> polling. For long pauses (hours or more), the agent would need to poll indefinitely with no indication of when to stop, making suspension operationally equivalent to termination. Terminating the mission and creating a new one is cleaner — the PS retains the old mission's log for audit, and the new mission can be scoped appropriately for the changed circumstances that prompted the pause. This keeps mission lifecycle simple: a mission is alive until it is done.</t>
</section>

<section anchor="why-downstream-scope-is-not-constrained-by-upstream-scope"><name>Why Downstream Scope Is Not Constrained by Upstream Scope</name>
<t>In multi-hop scenarios, downstream authorization is intentionally not required to be a subset of upstream scopes. 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 prevent legitimate delegation chains. Instead, the PS evaluates each hop against the mission context, providing governance-based constraints that are more flexible than algebraic attenuation rules while maintaining a complete audit trail.</t>
</section>
</section>

<section anchor="comparisons-with-alternatives"><name>Comparisons with Alternatives</name>

<section anchor="why-not-mtls"><name>Why Not mTLS?</name>
<t>Mutual TLS (mTLS) authenticates the TLS connection, not individual HTTP requests. Different paths on the same resource may have different requirements — some paths may require no signature, others a signed request, others verified identity, and others an auth token. Per-request signatures allow resources to vary requirements by path. Additionally, mTLS requires PKI infrastructure (CA, certificate provisioning, revocation), cannot express progressive requirements, and is stripped by TLS-terminating proxies and CDNs. mTLS remains the right choice for infrastructure-level mutual authentication (e.g., service mesh). AAuth addresses application-level identity where progressive requirements and intermediary compatibility are needed.</t>
</section>

<section anchor="why-not-dpop"><name>Why Not DPoP?</name>
<t>DPoP (<xref target="RFC9449"/>) binds an existing OAuth access token to a key, preventing token theft. AAuth differs in that agents can establish identity from zero — no pre-existing token, no pre-registration. At the signature level (<xref target="I-D.hardt-httpbis-signature-key"/>), AAuth requires no tokens at all, only a signed request. DPoP has a single mode (prove you hold the key bound to this token), while AAuth supports progressive requirements from pseudonymous access through verified identity to authorized access with interactive consent. DPoP is the right choice for adding proof-of-possession to existing OAuth deployments.</t>
</section>

<section anchor="why-not-extend-gnap"><name>Why Not Extend GNAP</name>
<t>GNAP (<xref target="RFC9635"/>) shares several motivations with AAuth — proof-of-possession by default, client identity without pre-registration, and async authorization. A natural question is whether AAuth's capabilities could be achieved as GNAP extensions rather than a new protocol. There are several reasons they cannot.</t>
<t><strong>Resource tokens require an architectural change, not an extension.</strong> In GNAP, as in OAuth, the resource server is a passive consumer of tokens — it verifies them but never produces signed artifacts that the access server consumes. AAuth's resource tokens invert this: the resource cryptographically asserts what is being requested, binding its own identity, the agent's key thumbprint, and the requested scope into a signed JWT. Adding this to GNAP would require changing its core architectural assumption about the role of the resource server.</t>
<t><strong>Interaction chaining requires a different continuation model.</strong> GNAP's continuation mechanism operates between a single client and a single access server. When a resource needs to access a downstream resource that requires user consent, GNAP has no mechanism for that consent requirement to propagate back through the call chain to the original user. Supporting this would require rethinking GNAP's continuation model to support multi-party propagation through intermediaries.</t>
<t><strong>The federation model is fundamentally different.</strong> In GNAP, the client must discover and interact with each access server directly. AAuth's model — where the agent only ever talks to its PS, and the PS federates with resource ASes — is a different trust topology, not a configuration option. Retrofitting this into GNAP would produce a profile so constrained that it would be a distinct protocol in practice.</t>
<t><strong>GNAP's generality is a liability for this use case.</strong> GNAP is designed to be maximally flexible — interaction modes, key proofing methods, token formats, and access structures are all pluggable. This means implementers must make dozens of profiling decisions before arriving at an interoperable system. AAuth makes these decisions prescriptively: one token format (JWT), one key proofing method (HTTP Message Signatures), one interaction pattern (interaction codes with polling), and one identity model (<tt>local@domain</tt> with HTTPS metadata). For the agent-to-resource ecosystem, this prescriptiveness is a feature — it enables interoperability without bilateral agreements.</t>
<t>In summary, AAuth's core innovations — resource-signed challenges, interaction chaining through multi-hop calls, PS-to-AS federation, mission-scoped authorization, and clarification chat during consent — are architectural choices that would require changing GNAP's foundations rather than extending them. The result would be a heavily constrained GNAP profile that shares little with other GNAP deployments.</t>
</section>

<section anchor="why-not-extend-www-authenticate"><name>Why Not Extend WWW-Authenticate?</name>
<t><tt>WWW-Authenticate</tt> (<xref target="RFC9110"/>, Section 11.6.1) tells the client which authentication scheme to use. Its challenge model is "present credentials" — it cannot express progressive requirements, authorization, or deferred approval, and it cannot appear in a <tt>202 Accepted</tt> response.</t>
<t><tt>AAuth-Requirement</tt> and <tt>Accept-Signature</tt> coexist with <tt>WWW-Authenticate</tt>. A <tt>401</tt> response MAY include multiple headers, and the client uses whichever it understands:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
Accept-Signature: sig=("@method" "@authority" "@path");sigkey=uri
]]>
</sourcecode>
<t>A <tt>402</tt> response MAY include <tt>WWW-Authenticate</tt> for payment (e.g., the Payment scheme defined by the Micropayment Protocol (<xref target="I-D.ryan-httpauth-payment"/>)) alongside <tt>Accept-Signature</tt> for authentication or <tt>AAuth-Requirement</tt> for authorization:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 402 Payment Required
WWW-Authenticate: Payment id="x7Tg2pLq", method="example",
    request="eyJhbW91bnQiOiIxMDAw..."
Accept-Signature: sig=("@method" "@authority" "@path");sigkey=jkt
]]>
</sourcecode>
</section>

<section anchor="why-not-extend-oauth"><name>Why Not Extend OAuth?</name>
<t>OAuth 2.0 (<xref target="RFC6749"/>) was designed for delegated access — a user authorizes a pre-registered client to act on their behalf at a specific server. Extending OAuth for agent-to-resource authorization would require changing its foundational assumptions:</t>

<ul spacing="compact">
<li><strong>Client identity</strong>: OAuth clients have no independent identity. A <tt>client_id</tt> is issued by each authorization server — it is meaningless outside that relationship. AAuth agents have self-sovereign identity (<tt>aauth:local@domain</tt>) verifiable by any party.</li>
<li><strong>Pre-registration</strong>: OAuth requires clients to register with each authorization server before use. AAuth agents call resources they have never contacted before — the first API call is the registration.</li>
<li><strong>Bearer tokens</strong>: OAuth access tokens are bearer credentials — anyone who holds the token can use it. AAuth binds every token to a signing key via HTTP Message Signatures — a stolen token is useless without the private key.</li>
<li><strong>No resource identity</strong>: OAuth does not cryptographically identify the resource. AAuth resources sign resource tokens, binding their identity to the authorization flow.</li>
<li><strong>No governance layer</strong>: OAuth has no concept of missions, permission endpoints, audit logging, or interaction relay. These would need to be built on top as extensions, losing the coherence of a protocol designed around them.</li>
<li><strong>No federation model</strong>: OAuth's authorization server is always the resource owner's server. AAuth separates the person server (user's choice) from the access server (resource's choice) and defines how they federate.</li>
</ul>
<t>The Model Context Protocol (MCP) illustrates these limitations. MCP adopted OAuth 2.1 for agent-to-server authorization and immediately needed Dynamic Client Registration (<xref target="RFC7591"/>) because agents cannot pre-register with every server. But Dynamic Client Registration gives the agent a different <tt>client_id</tt> at each server — the agent still has no portable identity. Tokens are bearer credentials, so a stolen token grants full access. There is no resource identity — the server does not cryptographically prove who it is. There is no governance layer — no missions, no permission management, no audit trail. And the entire authorization model is per-server: each MCP server has its own authorization server, and the agent must discover and register with each one independently. MCP's experience demonstrates that OAuth can be made to work for the first API call, but it cannot provide the identity, governance, and federation that agents need as they operate across trust domains.</t>
<t>Rather than layer these changes onto OAuth — which would break backward compatibility and produce something unrecognizable — AAuth is a new protocol designed for the agent model from the ground up. AAuth complements OAuth: resources can wrap existing OAuth infrastructure behind the AAuth-Access token, and PSes can delegate user authentication to OpenID Connect providers.</t>
</section>
</section>
</section>

</back>

</rfc>
