Internet-Draft AAuth March 2026
Hardt Expires 6 September 2026 [Page]
Workgroup:
TBD
Internet-Draft:
draft-hardt-aauth-latest
Published:
Intended Status:
Standards Track
Expires:
Author:
D. Hardt
Hellō

AAuth Protocol

Abstract

AAuth is an authentication and authorization protocol for modern distributed systems. It provides progressive authentication from abuse prevention to full authorization, verified agent identity alongside user identity, cryptographic proof of resource legitimacy, and unified authentication and authorization in a single flow. The protocol uses HTTP Message Signatures for proof-of-possession on every request, eliminating bearer tokens and shared secrets. Any endpoint may return deferred responses using standard HTTP async semantics (202 Accepted, Location, Prefer: wait), enabling uniform handling of user interaction, long-running authorization, and clarification chat.

Discussion Venues

Note: This section is to be removed before publishing as an RFC.

Source for this draft and an issue tracker can be found at https://github.com/DickHardt/draft-hardt-aauth.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 6 September 2026.

Table of Contents

1. Introduction

OAuth 2.0 [RFC6749] was created to solve a specific problem: users were sharing their passwords with third-party web applications so those applications could access their data at other sites. OAuth replaced this anti-pattern with a delegation model — the user's browser redirects to the authorization server, the user consents, and the application receives an access token without ever seeing the user's credentials. OpenID Connect extended this to federated login. Together, they serve these use cases well and continue to be the right choice for them.

But the landscape has changed. New use cases have emerged that OAuth and OIDC were not designed to address:

The AAuth protocol is designed for these new use cases. It complements OAuth and OIDC rather than replacing them — where pre-registered clients, browser redirects, bearer tokens, and static scopes work well, they remain the right choice.

AAuth provides:

2. Conventions and Definitions

{::boilerplate bcp14-tagged}

3. Terminology

Agent
An application or software component acting on behalf of a user or autonomously. In AAuth, agents have cryptographic identity and all requests are signed. An agent may also request auth tokens for itself — for SSO (user identity) or first-party resource access — where the agent is the audience.
Agent Server
A server that manages agent identity and issues agent tokens to agent delegates. Identified by an HTTPS URL and publishes metadata at /.well-known/aauth-agent.json.
Agent Delegate
An instance of an agent that holds an agent token and makes requests on behalf of the agent. Each delegate has its own signing key and unique identifier.
Agent Token
A JWT issued by an agent server to an agent delegate, binding the delegate's signing key to the agent's identity.
Auth Server
A server that authenticates users, obtains consent, evaluates authorization policies, and issues auth tokens. Publishes metadata at /.well-known/aauth-issuer.json.
Auth Token
A JWT issued by an auth server that grants an agent access to a resource, containing user identity and/or authorized scopes.
Resource
A protected API at a service that requires authentication and/or authorization. Like agents, resources have cryptographic identity via an HTTPS URL and publish metadata at /.well-known/aauth-resource.json.
Resource Token
A JWT issued by a resource that binds an access request to the resource's identity, preventing confused deputy attacks (see Security Considerations).
Interaction Endpoint
A URL where the user is sent for authentication, consent, or other interaction. Declared as interaction_endpoint in entity metadata. Both auth servers and resources may have interaction endpoints.
Interaction Code
A short alphanumeric code that links an agent's pending request to the user's interaction at an interaction endpoint.

4. Protocol Overview

AAuth has three participant types — agents, resources, and auth servers — though not all participate in every use case.

4.1. Request Signing

All AAuth requests are signed using HTTP Message Signatures ([RFC9421]). Keys are conveyed in the Signature-Key header ([I-D.hardt-httpbis-signature-key]). When the agent includes its public key directly (using scheme=hwk), the request is pseudonymous — the signature proves possession of the included key without establishing verified identity. When the agent presents a JWT (agent token or auth token) via scheme=jwt, the JWT's cnf claim binds the signing key to a verified identity or authorization.

4.2. Token Types

AAuth defines three token types, all of which are proof-of-possession tokens:

  • Agent Token (agent+jwt): Binds an agent delegate's key to an agent server's identity
  • Resource Token (resource+jwt): Binds an access request to a resource's identity
  • Auth Token (auth+jwt): Binds identity claims and authorization for a given audience to an agent

All three token types use the cnf (confirmation) claim ([RFC7800]) to bind the token to a specific signing key, making them proof-of-possession tokens usable only by a specific agent.

4.3. Requirement Levels

Resources and auth servers indicate what is needed from the agent using the AAuth HTTP response header.

4.3.1. Request Requirements

These are returned as 401 responses from resources, indicating what the agent must provide:

  1. Pseudonym (require=pseudonym): Signed request proves possession of an included public key, providing consistent identity without verification
  2. Identified (require=identity): Agent identity verified via JWKS or agent token
  3. Authorized (require=auth-token): Full authorization with auth token

4.3.2. Pending States

These are returned as 202 responses during authorization, indicating what must happen before the request can complete:

  1. Interaction (require=interaction): The agent must direct the user to the interaction endpoint with the provided code
  2. Approval (require=approval): The auth server is obtaining approval directly from a user or policy evaluation — the agent polls until resolved

4.4. Scopes

Scopes may request identity claims (using OpenID Connect scope values such as openid, profile, email) or resource authorization (using scopes defined by the resource, such as data.read or calendar.write as defined in the resource's scope_descriptions metadata), or both.

When the agent is the audience, scopes typically request identity claims. When accessing a resource, scopes are defined in the resource's scope_descriptions metadata.

Agents MAY act as a resource and include scope_descriptions in their metadata to enable users to grant scopes to resources at the agent during consent, enabling an agent delegate to obtain consent to access protected resources at the agent.

When an agent needs additional scopes beyond its current authorization, it requests a new auth token from the auth server's token_endpoint — with a new resource_token when accessing another resource, or with the new scope values when the agent is the audience. The new auth token replaces the previous one.

4.5. Flows

4.5.1. Pseudonymous Access

An agent accesses a resource that requires pseudonymous identity. The resource challenges with require=pseudonym, and the agent retries with a signed request using an inline public key. The resource can track the agent by key thumbprint without knowing its identity.

Agent                          Resource
  |                               |
  |  unsigned request             |
  |------------------------------>|
  |                               |
  |  401 Unauthorized             |
  |  AAuth: require=pseudonym     |
  |<------------------------------|
  |                               |
  |  HTTPSig request              |
  |  (scheme=hwk)                 |
  |------------------------------>|
  |                               |
  |            verify signature,  |
  |            track by key       |
  |            thumbprint         |
  |                               |
  |  200 OK                       |
  |<------------------------------|
  |                               |

If the agent already knows the resource requires pseudonymous access (from a previous interaction or metadata), it MAY sign the initial request directly without waiting for a 401 challenge.

4.5.2. Agent Identity Only

An agent accesses a resource using only its agent identity, without authorization from an auth server.

Agent                          Resource
  |                               |
  |  HTTPSig request              |
  |  (scheme=jwks_uri or jwt)     |
  |------------------------------>|
  |                               |
  |                  verify agent identity
  |                               |
  |  200 OK                       |
  |<------------------------------|
  |                               |

4.5.3. Autonomous Agent (Direct Grant)

A machine-to-machine agent obtains authorization directly without user interaction.

Agent                    Resource                  Auth Server
  |                         |                          |
  |  HTTPSig request        |                          |
  |------------------------>|                          |
  |                         |                          |
  |  401 + resource_token   |                          |
  |  + auth_server          |                          |
  |<------------------------|                          |
  |                         |                          |
  |  POST token_endpoint with resource_token           |
  |--------------------------------------------------->|
  |                         |                          |
  |                         |       validate resource_token,
  |                         |       evaluate policy    |
  |                         |                          |
  |  auth_token (direct grant)                         |
  |<---------------------------------------------------|
  |                         |                          |
  |  HTTPSig request        |                          |
  |  (with auth-token)      |                          |
  |------------------------>|                          |
  |                         |                          |
  |  200 OK                 |                          |
  |<------------------------|                          |
  |                         |                          |

4.5.4. User Authorization

Full flow with deferred response and polling for user-authorized access.

User            Agent                Resource           Auth Server
  |               |                      |                    |
  |               |  HTTPSig request     |                    |
  |               |--------------------->|                    |
  |               |                      |                    |
  |               |  401 + resource_token                     |
  |               |  + auth_server       |                    |
  |               |<---------------------|                    |
  |               |                      |                    |
  |               |  POST token_endpoint                      |
  |               |  resource_token, purpose                  |
  |               |  Prefer: wait=45                          |
  |               |------------------------------------------>|
  |               |                      |                    |
  |               |  202 Accepted, Location: /pending/abc     |
  |               |  AAuth: require=interaction;              |
  |               |         code="ABCD1234"                   |
  |               |<------------------------------------------|
  |               |                      |                    |
  |  direct to    |                      |                    |
  |  interaction_endpoint                |                    |
  |  with code    |                      |                    |
  |<--------------|                      |                    |
  |               |                      |                    |
  |               |    [polling]         |                    |
  |               |  GET /pending/abc    |                    |
  |               |------------------------------------------>|
  |               |  202 Accepted        |                    |
  |               |<------------------------------------------|
  |               |                      |                    |
  |  authenticate and consent            |                    |
  |------------------------------------------------------>----|
  |               |                      |                    |
  |  redirect to callback_url            |                    |
  |<----------------------------------------------------------|
  |               |                      |                    |
  |  callback     |                      |                    |
  |-------------->|                      |                    |
  |               |                      |                    |
  |               |  GET /pending/abc    |                    |
  |               |------------------------------------------>|
  |               |  200 OK, auth_token  |                    |
  |               |<------------------------------------------|
  |               |                      |                    |
  |               |  HTTPSig request     |                    |
  |               |  (with auth-token)   |                    |
  |               |--------------------->|                    |
  |               |                      |                    |
  |               |  200 OK              |                    |
  |               |<---------------------|                    |
  |               |                      |                    |

4.5.5. Agent as Audience

An agent requests an auth token where it is the audience — either for SSO (obtaining user identity) or for first-party resource access by its delegates. The agent calls the token endpoint with scope (and no resource_token), since the agent itself is the resource.

User           Agent                        Auth Server
  |              |                               |
  |              |  POST token_endpoint          |
  |              |  scope (no resource_token)    |
  |              |  Prefer: wait=45              |
  |              |------------------------------>|
  |              |                               |
  |              |  202 Accepted                 |
  |              |  Location: /pending/def       |
  |              |  AAuth: require=interaction;  |
  |              |         code="EFGH5678"       |
  |              |<------------------------------|
  |              |                               |
  |  direct to   |                               |
  |  interaction_endpoint with code              |
  |<-------------|                               |
  |              |                               |
  |  authenticate and consent                    |
  |--------------------------------------------->|
  |              |                               |
  |  redirect to callback_url                    |
  |<---------------------------------------------|
  |              |                               |
  |              |  GET /pending/def             |
  |              |------------------------------>|
  |              |  200 OK, auth_token           |
  |              |<------------------------------|
  |              |                               |
  |              |  auth_token used for:         |
  |              |  1. User identity (SSO)       |
  |              |  2. API access by delegates   |
  |              |                               |

4.5.6. Direct Approval

The auth server obtains approval directly — from a user (e.g., push notification, existing session, email) — without the agent facilitating a redirect. The agent simply polls until the request resolves.

User              Agent                Resource           Auth Server
  |                 |                      |                    |
  |                 |  HTTPSig request     |                    |
  |                 |--------------------->|                    |
  |                 |                      |                    |
  |                 |  401 + resource_token                     |
  |                 |  + auth_server       |                    |
  |                 |<---------------------|                    |
  |                 |                      |                    |
  |                 |  POST token_endpoint                      |
  |                 |  resource_token, purpose                  |
  |                 |  Prefer: wait=45                          |
  |                 |------------------------------------------>|
  |                 |                      |                    |
  |                 |  202 Accepted                             |
  |                 |  Location: /pending/jkl                   |
  |                 |  AAuth: require=approval                  |
  |                 |<------------------------------------------|
  |                 |                      |                    |
  |  push notification / existing session  |                    |
  |<------------------------------------------------------------|
  |                 |                      |                    |
  |  approve        |                      |                    |
  |------------------------------------------------------------>|
  |                 |                      |                    |
  |                 |  GET /pending/jkl    |                    |
  |                 |  Prefer: wait=45     |                    |
  |                 |------------------------------------------>|
  |                 |  200 OK, auth_token  |                    |
  |                 |<------------------------------------------|
  |                 |                      |                    |
  |                 |  HTTPSig request     |                    |
  |                 |  (with auth-token)   |                    |
  |                 |--------------------->|                    |
  |                 |                      |                    |
  |                 |  200 OK              |                    |
  |                 |<---------------------|                    |
  |                 |                      |                    |

In this flow, the auth server handles the approval process directly. The require=approval value tells the agent that the request is waiting on external approval, but the agent does not need to facilitate any user interaction.

4.5.7. Resource Interaction

When a resource requires user interaction (login, consent for downstream access), it returns 202 Accepted with a Location header and AAuth: require=interaction; code="...". Resource-level user interaction is a deferral, not a denial — the request has been accepted but requires user action before it can complete.

The agent directs the user to the resource's interaction_endpoint with the interaction code. The resource handles the interaction (which may involve its own AAuth, OAuth, or OIDC flow with a downstream auth server). After completion, the resource redirects the user back to the agent's callback URL. The agent polls the Location URL with GET until the response is ready.

User            Agent                Resource           Auth Server
  |               |                      |                    |
  |               |  HTTPSig request     |                    |
  |               |  (with auth-token)   |                    |
  |               |--------------------->|                    |
  |               |                      |                    |
  |               |  202 Accepted        |                    |
  |               |  Location: /pending/xyz                   |
  |               |  AAuth: require=interaction;              |
  |               |         code="MNOP3456"                   |
  |               |<---------------------|                    |
  |               |                      |                    |
  |  direct to resource                  |                    |
  |  interaction_endpoint with code      |                    |
  |<--------------|                      |                    |
  |               |                      |                    |
  |  authenticate/consent                |                    |
  |------------------------------------->|                    |
  |               |                      |                    |
  |               |          [Resource may perform AAuth,     |
  |               |           OAuth, or OIDC flow]            |
  |               |                      |                    |
  |  redirect to callback_url            |                    |
  |<-------------------------------------|                    |
  |               |                      |                    |
  |  callback     |                      |                    |
  |-------------->|                      |                    |
  |               |                      |                    |
  |               |  GET /pending/xyz    |                    |
  |               |--------------------->|                    |
  |               |                      |                    |
  |               |  200 OK              |                    |
  |               |<---------------------|                    |
  |               |                      |                    |

The agent directs the user to the resource's interaction URL with the code. For a direct redirect:

https://resource.example/interact?code="MNOP3456"&callback=https%3A%2F%2Fagent.example%2Fcallback%3Fstate%3Dxyz

After user interaction completes, the agent polls the pending URL:

GET /pending/xyz HTTP/1.1
Host: resource.example
Prefer: wait=45
Signature-Input: sig=("@method" "@authority" "@path" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

4.5.8. Call Chaining

Editor's Note: Call chaining is an exploratory feature. The mechanism described here may change in future versions.

When a resource needs to access a downstream resource on behalf of the caller, it acts as an agent. The resource presents the downstream resource's resource token along with the auth token it received from the original caller as the upstream_token. This allows the downstream auth server to verify the authorization chain.

The downstream auth server (AS2) evaluates its own policy based on both the upstream auth token and the resource token from Resource 2. The resulting authorization is not necessarily a subset of the upstream scopes — AS2 may grant scopes that are independent of those in the upstream auth token. For example, an upstream token granting calendar.read on Resource 1 might lead AS2 to grant availability.read on Resource 2 based on an organizational policy that allows calendar services to query availability. The upstream token provides provenance and user identity context, not a scope ceiling.

Because the resource acts as an agent, it MUST publish agent metadata at /.well-known/aauth-agent.json (see Agent Server Metadata) so that downstream resources and auth servers can verify its identity. The resource / agent MAY use the same jwks_uri in the /.well-known/aauth-resource.json and the /.well-known/aauth-agent.json.

4.5.8.1. Direct Grant

When the downstream auth server can issue a token without user interaction:

Agent          Resource 1        Resource 2         AS1           AS2
  |                |                  |               |             |
  |  HTTPSig req   |                  |               |             |
  |  (auth_token   |                  |               |             |
  |   from AS1)    |                  |               |             |
  |--------------->|                  |               |             |
  |                |                  |               |             |
  |           verify auth_token       |               |             |
  |                |                  |               |             |
  |                |  HTTPSig req     |               |             |
  |                |  (as agent)      |               |             |
  |                |----------------->|               |             |
  |                |                  |               |             |
  |                |  401 + resource_token            |             |
  |                |  + auth_server=AS2               |             |
  |                |<-----------------|               |             |
  |                |                  |               |             |
  |                |  POST token_endpoint             |             |
  |                |  resource_token from R2,         |             |
  |                |  upstream_token (from AS1)       |             |
  |                |----------------------------------------------->|
  |                |                  |               |             |
  |                |                  |       verify upstream_token,|
  |                |                  |       evaluate policy       |
  |                |                  |       (fetch AS1 JWKS)      |
  |                |                  |               |             |
  |                |  auth_token for R2                |            |
  |                |<-----------------------------------------------|
  |                |                  |               |             |
  |                |  HTTPSig req     |               |             |
  |                |  (auth_token     |               |             |
  |                |   from AS2)      |               |             |
  |                |----------------->|               |             |
  |                |                  |               |             |
  |                |  200 OK          |               |             |
  |                |<-----------------|               |             |
  |                |                  |               |             |
  |  200 OK        |                  |               |             |
  |<---------------|                  |               |             |
  |                |                  |               |             |

4.5.8.2. Interaction Chaining

When the downstream auth server requires user interaction, Resource 1 chains the interaction back to the original agent. Resource 1 receives a 202 with require=interaction from the downstream auth server, then returns its own 202 with require=interaction to the agent. The agent directs the user to Resource 1's interaction endpoint, and Resource 1 redirects the user onward to the downstream interaction endpoint. This keeps the downstream interaction URL opaque to the agent — each link in the chain manages only its own interaction redirect.

User         Agent          Resource 1        Resource 2          AS2
  |            |                 |                 |                |
  |            |  HTTPSig req    |                 |                |
  |            |---------------->|                 |                |
  |            |                 |                 |                |
  |            |                 |  HTTPSig req    |                |
  |            |                 |  (as agent)     |                |
  |            |                 |---------------->|                |
  |            |                 |                 |                |
  |            |                 |  401 + resource_token            |
  |            |                 |  + auth_server=AS2               |
  |            |                 |<----------------|                |
  |            |                 |                 |                |
  |            |                 |  POST token_endpoint             |
  |            |                 |  with upstream_token             |
  |            |                 |--------------------------------->|
  |            |                 |                 |                |
  |            |                 |  202 Accepted                    |
  |            |                 |  require=interaction;            |
  |            |                 |  code=WXYZ                       |
  |            |                 |<---------------------------------|
  |            |                 |                 |                |
  |            |  202 Accepted   |                 |                |
  |            |  Location: /pending/xyz           |                |
  |            |  AAuth: require=interaction;      |                |
  |            |         code="MNOP"               |                |
  |            |<----------------|                 |                |
  |            |                 |                 |                |
  |  direct to R1                |                 |                |
  |  interaction_endpoint        |                 |                |
  |  with code |                 |                 |                |
  |<-----------|                 |                 |                |
  |            |                 |                 |                |
  |  interaction_endpoint        |                 |                |
  |----------------------------->|                 |                |
  |            |                 |                 |                |
  |  redirect to AS2 interaction_endpoint          |                |
  |<-----------------------------|                 |                |
  |            |                 |                 |                |
  |  authenticate and consent    |                 |                |
  |---------------------------------------------------------------->|
  |            |                 |                 |                |
  |  redirect to R1 callback     |                 |                |
  |<----------------------------------------------------------------|
  |            |                 |                 |                |
  |            |            [R1 polls AS2 pending URL,              |
  |            |             receives auth_token for R2]            |
  |            |                 |                 |                |
  |            |                 |  HTTPSig req    |                |
  |            |                 |  (auth_token    |                |
  |            |                 |   from AS2)     |                |
  |            |                 |---------------->|                |
  |            |                 |                 |                |
  |            |                 |  200 OK         |                |
  |            |                 |<----------------|                |
  |            |                 |                 |                |
  |  redirect to agent callback_url                |                |
  |<-----------------------------|                 |                |
  |            |                 |                 |                |
  |  callback  |                 |                 |                |
  |----------->|                 |                 |                |
  |            |                 |                 |                |
  |            |  GET /pending/xyz                 |                |
  |            |---------------->|                 |                |
  |            |                 |                 |                |
  |            |  200 OK         |                 |                |
  |            |<----------------|                 |                |
  |            |                 |                 |                |

5. Identifier and URL Requirements

5.1. Server Identifiers

The agent, resource, and issuer values that identify agents, resources, and auth servers MUST conform to the following:

  • MUST use the https scheme
  • MUST contain only scheme and host (no port, path, query, or fragment)
  • MUST NOT include a trailing slash
  • MUST be lowercase
  • Internationalized domain names MUST use the ASCII-Compatible Encoding (ACE) form (A-labels) as defined in [RFC5890]

Valid identifiers:

  • https://agent.example
  • https://xn--nxasmq6b.example (internationalized domain in ACE form)

Invalid identifiers:

  • http://agent.example (not HTTPS)
  • https://Agent.Example (not lowercase)
  • https://agent.example:8443 (contains port)
  • https://agent.example/v1 (contains path)
  • https://agent.example/ (trailing slash)

Implementations MUST perform exact string comparison on server identifiers. The lowercase and ACE requirements ensure that normalization happens at the source rather than requiring comparison logic at every point of use.

5.2. Endpoint URLs

The token_endpoint, interaction_endpoint, resource_token_endpoint, and callback_endpoint values MUST conform to the following:

  • MUST use the https scheme
  • MUST NOT contain a fragment
  • MUST NOT contain a query string

When localhost_callback_allowed is true in the agent's metadata, the agent MAY use a localhost callback URL as the callback parameter to the interaction endpoint. Localhost callback URLs MUST use the http scheme with a loopback address (127.0.0.1, [::1], or localhost), MUST include a port, MAY include a path, and MUST NOT contain a query string or fragment.

5.3. Other URLs

The jwks_uri, tos_uri, policy_uri, logo_uri, and logo_dark_uri values MUST use the https scheme.

6. AAuth HTTP Response Header

Servers use the AAuth response header to indicate authentication and interaction requirements. The header value is a Structured Fields Dictionary ([RFC8941]) with a require key whose token value indicates the requirement level. Additional parameters provide context for the requirement.

6.1. Pseudonym Required

When a resource requires only a signed request:

HTTP/1.1 401 Unauthorized
AAuth: require=pseudonym

6.2. Identity Required

When a resource requires verified agent identity:

HTTP/1.1 401 Unauthorized
AAuth: require=identity

6.3. Auth Token Required

When a resource requires an auth token:

HTTP/1.1 401 Unauthorized
AAuth: require=auth-token; resource-token="..."; auth-server="https://auth.example"

Parameters:

  • resource-token: A resource token binding this request to the resource's identity
  • auth-server: The auth server URL where the agent should obtain an auth token

6.4. Interaction Required

When a server requires user interaction, it returns 202 Accepted per the Deferred Responses protocol with an AAuth header and a JSON body:

HTTP/1.1 202 Accepted
Location: /pending/res_abc123
Retry-After: 0
Cache-Control: no-store
AAuth: require=interaction; code="ABCD1234"
Content-Type: application/json

{
  "status": "pending",
  "location": "/pending/res_abc123",
  "require": "interaction",
  "code": "ABCD1234"
}

The code field is REQUIRED when require is "interaction". The agent MUST direct the user to the server's interaction_endpoint with the code and poll the Location URL with GET for the result.

6.5. Approval Pending

When the auth server is obtaining approval directly — from a user (e.g., push notification, existing session) — without the agent's involvement:

HTTP/1.1 202 Accepted
Location: /pending/res_def456
AAuth: require=approval
Retry-After: 0
Cache-Control: no-store
Content-Type: application/json

{
  "status": "pending",
  "location": "/pending/res_def456",
  "require": "approval"
}

The agent knows the request is waiting on external approval but does not need to take any action. The agent polls the Location URL until the request resolves.

7. Agent Tokens

Agent tokens enable agent servers to delegate signing authority to agent delegates while maintaining a stable agent identity.

7.1. Agent Token Structure

An agent token is a JWT with typ: agent+jwt containing:

Header: - alg: Signing algorithm - typ: agent+jwt - kid: Key identifier

Required payload claims: - iss: Agent server URL (the agent identifier) - sub: Agent delegate identifier (stable across key rotations) - jti: Unique token identifier for replay detection and audit - cnf: Confirmation claim ([RFC7800]) with jwk containing the delegate's public key - iat: Issued at timestamp - exp: Expiration timestamp

Optional payload claims: - aud: Audience restriction. When present, the agent delegate MUST only present this agent token to the specified server(s). The value is a single URL or an array of URLs identifying the auth server(s) or resource(s) where this token is valid. Servers receiving an agent token with an aud claim MUST verify that their own identifier is listed. - aud_sub: The user identifier (sub value) from a previous auth token issued by the auth server in aud. This signals to the auth server which user the agent server believes the delegate is acting on behalf of, enabling the auth server to skip interactive identification and proceed directly to authorization. The auth server MUST verify this claim against its own records and MAY ignore it if the binding is no longer valid.

When aud is absent, the agent token establishes agent identity across all interactions — the delegate uses the same agent token regardless of which resource or auth server it communicates with. When aud is present, the agent server is restricting the delegate to specific interactions, which limits exposure if the delegate's key is compromised.

Agent servers MAY include additional claims in the agent token to convey attestation evidence about the delegate's environment — for example, platform integrity, secure enclave status, or workload identity assertions. The semantics and verification of such claims are outside the scope of this specification but provide an extension point for deployments requiring stronger trust signals about agent delegates.

7.2. Agent Token Usage

Agent delegates present agent tokens via the Signature-Key header using scheme=jwt:

Signature-Key: sig=jwt; jwt="eyJhbGciOiJFZERTQSIsInR5cCI6ImFnZW50K2p3dCJ9..."

8. Resource Tokens

Resource tokens provide cryptographic proof of resource identity, preventing confused deputy and MITM attacks.

8.1. Resource Token Structure

A resource token is a JWT with typ: resource+jwt containing:

Header: - alg: Signing algorithm - typ: resource+jwt - kid: Key identifier

Payload: - iss: Resource URL - aud: Auth server URL - jti: Unique token identifier for replay detection and audit - agent: Agent identifier - agent_jkt: JWK Thumbprint ([RFC7638]) of the agent's current signing key - iat: Issued at timestamp - exp: Expiration timestamp - scope: Requested scopes (optional) - txn: Transaction identifier (optional). When present, correlates this resource token with the resulting auth token and all related protocol exchanges across parties and audit logs.

8.2. Resource Token Usage

Resources include resource tokens in the AAuth header when requiring authorization:

AAuth: require=auth-token; resource-token="eyJ..."; auth-server="https://auth.example"

8.3. Resource Token Endpoint

When a resource publishes a resource_token_endpoint in its metadata, agents MAY request a resource token proactively — without first making an API call and receiving a 401 challenge. This enables two patterns:

  • Pre-authorization: The agent knows the scopes it needs (from the resource's scope_descriptions metadata) and obtains authorization before making its first API call.
  • Scope upgrade: The agent already has an auth token but needs additional scopes. It requests a new resource token with the broader scope, obtains a new auth token, and retries.

Request:

POST /resource-token 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"
}

Response:

{
  "resource_token": "eyJhbGc...",
  "auth_server": "https://auth.example",
  "scope": "data.read data.write"
}

The resource generates and signs a resource token and returns it along with the auth server URL and the granted scope. The scope in the response reflects what the resource included in the resource token, which MAY be narrower than what was requested. The agent then proceeds to the auth server's token endpoint as in the standard flow.

The resource MAY reject the request if the requested scopes are invalid or if the resource does not support proactive token requests for the given scopes:

{
  "error": "invalid_scope",
  "error_description": "Unknown scope: data.admin"
}

9. Auth Tokens

Auth tokens grant agents access to resources after authentication and authorization.

9.1. Auth Token Structure

An auth token is a JWT with typ: auth+jwt containing:

Header: - alg: Signing algorithm - typ: auth+jwt - kid: Key identifier

Required payload claims: - iss: Auth server URL - aud: The URL of the resource the agent is authorized to access. When the agent is accessing its own resources (SSO or first-party use), the aud is the agent server's URL. - jti: Unique token identifier for replay detection and audit - agent: Agent identifier - cnf: Confirmation claim with jwk containing the agent's public key - iat: Issued at timestamp - exp: Expiration timestamp

Conditional payload claims (at least one MUST be present): - sub: User identifier - scope: Authorized scopes

Conditional payload claims (REQUIRED when present in the resource token): - txn: Transaction identifier copied from the resource token's txn claim. Enables correlation of the authorization grant with the original resource request across all parties and audit logs.

Editor's Note: A future version may define a URI-based authorization claim (referencing a Rich Authorization Request document with a SHA-256 hash of the contents) as an alternative to scope.

The auth token MAY include additional claims registered in the IANA JSON Web Token Claims Registry [RFC7519] or defined in OpenID Connect Core 1.0 [OpenID.Core] Section 5.1.

9.2. Auth Token Usage

Agents present auth tokens via the Signature-Key header using scheme=jwt:

Signature-Key: sig=jwt; jwt="eyJhbGciOiJFZERTQSIsInR5cCI6ImF1dGgrand0In0..."

10. Deferred Responses

Any endpoint in AAuth — whether an auth server token endpoint or a resource endpoint — MAY return a 202 Accepted response ([RFC9110]) when it cannot immediately resolve a request. This is a first-class protocol primitive, not a special case. Agents MUST handle 202 responses regardless of the nature of the original request.

Reasons a 202 MAY be returned include:

10.1. Initial Request

The agent makes a request and signals its willingness to wait using the Prefer header ([RFC7240]):

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..."
}

The wait preference tells the server the agent is willing to hold the connection open for up to N seconds before the server MUST respond. The server confirms the honored duration with Preference-Applied:

Preference-Applied: wait=45

The server SHOULD respond within the requested wait duration. If the request cannot be resolved within that time, it returns a 202.

10.2. Pending Response

When the server cannot resolve the request within the wait period:

HTTP/1.1 202 Accepted
Location: /pending/f7a3b9c
Retry-After: 0
Cache-Control: no-store
Content-Type: application/json

{
  "status": "pending",
  "location": "/pending/f7a3b9c"
}

Headers:

  • Location (REQUIRED): The pending URL. The server embeds its state in the URL path. The Location URL MUST be on the same origin as the responding server.
  • Retry-After (REQUIRED): Seconds the agent SHOULD wait before polling. 0 means retry immediately.
  • Cache-Control: no-store (REQUIRED): Prevents caching of pending responses.

Every 202 response MUST include a Location header, making each response self-contained.

Body fields:

  • status (REQUIRED): Always "pending".
  • location (REQUIRED): The pending URL (echoes the Location header).
  • require (OPTIONAL): The requirement level. "interaction" when the agent must direct the user to an interaction endpoint (with code). "approval" when the auth server is obtaining approval directly from a user.
  • code (OPTIONAL): The interaction code. Present only with require: "interaction". The agent MUST direct the user to the server's interaction_endpoint with this code.
  • clarification (OPTIONAL): A question from the user during consent. Present during clarification chat.

10.3. Polling with GET

After receiving a 202, the agent switches to GET for all subsequent requests to the Location URL:

GET /pending/f7a3b9c HTTP/1.1
Host: auth.example
Prefer: wait=45
Signature-Input: sig=("@method" "@authority" "@path" "signature-key");created=1730217600
Signature: sig=:...signature bytes...:
Signature-Key: sig=jwt;jwt="eyJhbGc..."

  • The agent does NOT resend the original request body
  • The Location URL contains all state the server needs
  • The agent SHOULD include Prefer: wait=N on every poll
  • While still pending, the server responds with 202 including the same Location
  • Exception: During clarification chat, the agent uses POST to deliver a clarification response to the pending URL (see Clarification Chat). This is the only case where the agent sends a non-GET request to a pending URL.

The distinction between POST and GET is intentional:

  • POST — "here is my request, process this" — creates the pending context
  • GET — "give me the result" — idempotent, safe to retry on network failure

10.4. Terminal Responses

A non-202 response terminates polling. The agent MUST stop polling and handle the response.

Table 1
Status Meaning Agent Behavior
200 Success Process response body
403 Denied or abandoned Surface to user; check error field
408 Expired MAY initiate a fresh request
410 Gone — permanently invalid MUST NOT retry
500 Internal server error Start over

Once a terminal response is returned, the Location URL is no longer valid. Subsequent GET requests to it MUST return 404.

10.5. Transient Non-Terminal Responses

Table 2
Status Meaning Agent Behavior
202 Pending Continue polling with Prefer: wait
503 Server temporarily unavailable Back off using Retry-After; MUST honor over Prefer: wait

Error responses during deferred processing use the standard error response format defined in the Error Responses section.

10.6. Agent State Machine

Initial POST (with Prefer: wait=N)
    |
    +-- 200 --> done (direct grant)
    +-- 202 --> note Location URL, check require/code
    +-- 400 --> invalid_request or invalid_resource_token — fix and retry
    +-- 401 --> invalid_signature — check credentials
    +-- 500 --> server_error — start over
    +-- 503 --> back off (Retry-After), retry
               |
               GET Location (with Prefer: wait=N)
               |
               +-- 200 --> done
               +-- 202 --> continue polling (check for clarification)
               +-- 403 --> denied or abandoned — surface to user
               +-- 408 --> expired — MAY retry with fresh request
               +-- 410 --> invalid_code — do not retry
               +-- 500 --> server_error — start over
               +-- 503 --> temporarily_unavailable — back off (Retry-After)

11. Token Endpoint

The auth server's token_endpoint is the endpoint for initiating authorization requests and refreshing auth tokens. Polling and clarification use the pending URL returned in 202 responses (see Deferred Responses).

11.1. Token Endpoint Modes

The token endpoint serves multiple functions depending on the parameters provided:

Table 3
Mode Key Parameters Use Case
Resource access resource_token Agent needs auth token for a resource
Self-access (SSO/1P) scope (no resource_token) Agent needs auth token for itself
Call chaining resource_token + upstream_token Resource acting as agent
Token refresh auth_token (expired) Renew expired token

11.2. Authorization Request

The agent makes a signed POST to the token_endpoint to initiate an authorization request.

Request parameters:

  • resource_token (CONDITIONAL): The resource token from a resource's AAuth challenge or from the resource's resource_token_endpoint (see Resource Token Endpoint). Required when requesting access to another resource.
  • scope (CONDITIONAL): Space-separated scope values. Used when the agent requests authorization to itself (agent is resource).
  • upstream_token (OPTIONAL): An auth token from an upstream authorization, used in call chaining when a resource acts as an agent to access a downstream resource. Allows the auth server to verify the authorization chain.
  • purpose (OPTIONAL): Human-readable string declaring why access is being requested.
  • login_hint (OPTIONAL): Hint about who to authorize, per [OpenID.Core] Section 3.1.2.1.
  • tenant (OPTIONAL): Tenant identifier, per OpenID Connect Enterprise Extensions 1.0 [OpenID.Enterprise].
  • domain_hint (OPTIONAL): Domain hint, per OpenID Connect Enterprise Extensions 1.0 [OpenID.Enterprise].

Editor's Note: Future drafts may define additional parameters to indicate how the auth server should process the request, such as authentication strength requirements.

Example request:

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...",
  "purpose": "Find available meeting times"
}

11.3. Auth Server Response

The auth server validates the request and responds based on policy.

Direct grant response (200 — no user interaction needed):

{
  "auth_token": "eyJhbGc...",
  "expires_in": 3600
}

User interaction required response (202 — deferred):

HTTP/1.1 202 Accepted
Location: /pending/abc123
Retry-After: 0
Cache-Control: no-store
AAuth: require=interaction; code="ABCD1234"
Content-Type: application/json

{
  "status": "pending",
  "location": "/pending/abc123",
  "require": "interaction",
  "code": "ABCD1234"
}

The location field contains the pending URL the agent polls with GET. When require is "interaction", the agent directs the user to the auth server's interaction_endpoint with the code. When require is "approval", the auth server is obtaining approval directly from a user and the agent simply polls.

Error response (request validation failed):

{
  "error": "invalid_resource_token",
  "error_description": "Resource token has expired"
}

See Token Endpoint Error Codes in the Error Responses section for the full set of error codes.

Polling, terminal responses, and error handling follow the Deferred Responses protocol described above.

11.4. Clarification Chat

Agents that support clarification chat MUST declare "clarification_supported": true in their agent server metadata. Auth servers SHOULD only send clarification questions to agents that declare support. If the field is absent or false, the auth server MUST NOT include clarification in polling responses.

During user consent, the user may ask questions about the agent's stated purpose. The auth server delivers these questions to the agent, and the agent responds:

User                  Agent                     Auth Server
  |                     |                            |
  |      [Agent has Location URL;                    |
  |       user is at interaction_endpoint]           |
  |                     |                            |
  |                     |  GET /pending/abc          |
  |                     |  Prefer: wait=45           |
  |                     |--------------------------->|
  |                     |       [connection held open]
  |                     |                            |
  |  "Why do you need calendar access?"              |
  |------------------------------------------------->|
  |                     |                            |
  |                     |  202 with clarification    |
  |                     |  "Why do you need          |
  |                     |   calendar access?"        |
  |                     |<---------------------------|
  |                     |                            |
  |                     |  POST /pending/abc         |
  |                     |  "I need to find           |
  |                     |   available meeting        |
  |                     |   times for your           |
  |                     |   Tokyo trip next week"    |
  |                     |--------------------------->|
  |                     |                            |
  |  display agent response                          |
  |<-------------------------------------------------|
  |                     |                            |
  |  grant consent      |                            |
  |------------------------------------------------->|
  |                     |                            |
  |                     |  GET /pending/abc          |
  |                     |  Prefer: wait=45           |
  |                     |--------------------------->|
  |                     |  200 OK, auth_token        |
  |                     |<---------------------------|
  |                     |                            |

A 202 polling response may include a clarification field containing the user's question:

{
  "status": "pending",
  "location": "/pending/abc123",
  "clarification": "Why do you need access to my calendar?"
}

The agent responds by POSTing JSON with clarification_response to the pending URL:

POST /pending/abc123 HTTP/1.1
Host: auth.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 find available meeting times for your Tokyo trip next week"
}

Auth servers SHOULD enforce limits on clarification rounds (recommended: 5 rounds maximum) and overall timeout to prevent abuse.

11.5. User Interaction

When a server responds with 202 and AAuth: require=interaction; code="...", the agent directs the user to the server's interaction_endpoint with the interaction code. The agent has three options:

Manual entry: Display the interaction_endpoint and the code separately. The agent MAY insert hyphens into the code for readability (e.g., ABCD-1234). The code itself MUST NOT contain hyphens.

QR code: Encode the full URL for scanning:

{interaction_endpoint}?code={interaction_code}

Direct redirect (when the agent has a browser): Navigate the user directly, optionally with a callback:

{interaction_endpoint}?code={interaction_code}&callback={callback_url}

Example redirect URL:

https://auth.example/interact?code="ABCD1234"&callback=https%3A%2F%2Fagent.example%2Fcallback%3Fstate%3Dabc123

The server authenticates the user and displays consent information (including the agent's purpose, identity, and requested scopes).

After consent, the server determines the callback behavior:

If the agent provided a callback parameter, the server redirects the user to that URL:

HTTP/1.1 303 See Other
Location: https://agent.example/callback?state=abc123

If no callback was provided, the server displays a completion page telling the user they may close the window.

11.6. Token Refresh

When an auth token expires, the agent requests a new one by presenting the expired auth token.

Request:

POST /token HTTP/1.1
Host: auth.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..."

{
  "auth_token": "eyJhbGc..."
}

Response:

{
  "auth_token": "eyJhbGc...",
  "expires_in": 3600
}

The auth server verifies the agent's HTTP signature, validates the expired auth token, and issues a new auth token. The auth server MAY reject the refresh if the token has been expired beyond its refresh window.

12. Agent Delegate User Binding

An agent delegate SHOULD be associated with at most one user. The auth server tracks the association between an agent delegate (identified by the sub claim in the agent token) and the user who authorized it. The user may be anonymous to the agent and to the resource, but the auth server always knows who authorized the delegate.

This association enables:

13. Metadata Documents

Participants publish metadata at well-known URLs ([RFC8615]) to enable discovery.

13.1. Agent Server Metadata

Published at /.well-known/aauth-agent.json:

{
  "agent": "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,
  "clarification_supported": true,
  "tos_uri": "https://agent.example/tos",
  "policy_uri": "https://agent.example/privacy"
}

Fields:

  • agent (REQUIRED): The agent's HTTPS URL
  • jwks_uri (REQUIRED): URL to the agent's JSON Web Key Set
  • client_name (OPTIONAL): Human-readable agent name (per [RFC7591])
  • logo_uri (OPTIONAL): URL to agent logo (per [RFC7591])
  • logo_dark_uri (OPTIONAL): URL to agent logo for dark backgrounds
  • callback_endpoint (OPTIONAL): The agent's HTTPS callback endpoint URL. The agent MAY append path and query parameters at runtime to construct the callback URL — any URL on the same origin is valid. If absent, the agent does not support callbacks.
  • localhost_callback_allowed (OPTIONAL): Boolean indicating whether the agent supports localhost callbacks (for CLI tools and desktop applications). Default: false. When true, any http URL with a loopback address (127.0.0.1, [::1], or localhost) and a port is permitted as a callback URL at runtime.
  • clarification_supported (OPTIONAL): Boolean indicating whether the agent supports clarification chat during consent. Default: false.
  • tos_uri (OPTIONAL): URL to terms of service (per [RFC7591])
  • policy_uri (OPTIONAL): URL to privacy policy (per [RFC7591])

13.2. Auth Server Metadata

Published at /.well-known/aauth-issuer.json:

{
  "issuer": "https://auth.example",
  "token_endpoint": "https://auth.example/token",
  "interaction_endpoint": "https://auth.example/interact",
  "jwks_uri": "https://auth.example/.well-known/jwks.json"
}

Fields:

  • issuer (REQUIRED): The auth server's HTTPS URL
  • token_endpoint (REQUIRED): Single endpoint for all agent-to-auth-server communication
  • interaction_endpoint (REQUIRED): URL where users are sent for authentication and consent
  • jwks_uri (REQUIRED): URL to the auth server's JSON Web Key Set

13.3. Resource Metadata

Published at /.well-known/aauth-resource.json:

{
  "resource": "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",
  "resource_token_endpoint": "https://resource.example/resource-token",
  "interaction_endpoint": "https://resource.example/interact",
  "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"]
}

Fields:

  • resource (REQUIRED): The resource's HTTPS URL
  • jwks_uri (REQUIRED): URL to the resource's JSON Web Key Set
  • client_name (OPTIONAL): Human-readable resource name (per [RFC7591])
  • logo_uri (OPTIONAL): URL to resource logo (per [RFC7591])
  • logo_dark_uri (OPTIONAL): URL to resource logo for dark backgrounds
  • resource_token_endpoint (OPTIONAL): URL where agents can proactively request a resource token for specific scopes without first making an API call. See Resource Token Endpoint.
  • interaction_endpoint (OPTIONAL): URL where users are sent for resource-level interaction
  • scope_descriptions (OPTIONAL): Object mapping scope names to human-readable descriptions, for the auth server to use in consent UI
  • additional_signature_components (OPTIONAL): Additional HTTP message components that must be covered in signatures

14. Purpose

The purpose parameter is an optional human-readable string that an agent passes to the auth server when requesting an auth token. It declares why access is being requested, providing context for authorization decisions without requiring the auth server or resource to evaluate or enforce the stated purpose.

14.1. Usage

When an agent requests an auth token from the auth server, it MAY include a purpose parameter that describes the reason for the access request in terms meaningful to the authorizing user.

The auth server SHOULD present the purpose value to the user during consent. The auth server MAY log the purpose for audit and monitoring purposes. The purpose is also available to the user during clarification chat.

14.2. Security Considerations for Purpose

The purpose parameter enables an agent to provide context for a request that is part of a larger task initiated earlier. A user may have numerous outstanding tasks managed by different agents, and the purpose helps the user understand which task triggered a particular authorization request. For example:

  • "Find available meeting times for your Tokyo trip next week" — links calendar access to a specific travel-planning task
  • "Summarize the Q3 revenue spreadsheet you shared yesterday" — links file access to a prior document review
  • "Check inventory levels for the restock order you approved this morning" — links supply chain data access to an earlier purchasing decision
  • "Update your project timeline based on the delay Bob reported" — links project management access to a team communication context

Without purpose, the user sees only "Agent X wants calendar.read" with no way to distinguish which of their active tasks prompted the request.

The purpose parameter is self-asserted by the requesting agent or application. Auth servers and users SHOULD treat it as informational context, not as a trusted assertion. A malicious agent could declare a benign purpose while intending harmful actions.

However, the declared purpose creates accountability. If an agent declares its purpose is to "find available meeting times" but then reads email content, the discrepancy between declared purpose and actual behavior is detectable by monitoring systems.

15. HTTP Message Signing Profile

AAuth uses HTTP Message Signatures ([RFC9421]) for request authentication.

15.1. Required Headers

All AAuth requests MUST include:

  • Signature-Key: Public key or key reference for signature verification
  • Signature-Input: Signature metadata including covered components
  • Signature: The HTTP message signature

15.2. Signature-Key Header

The Signature-Key header ([I-D.hardt-httpbis-signature-key]) provides keying material:

  • scheme=hwk: Header Web Key (inline public key)
  • scheme=jwks_uri: Reference to JWKS endpoint
  • scheme=jwt: JWT containing public key in cnf claim
  • scheme=x509: X.509 certificate

15.3. Covered Components

HTTP Message Signatures in AAuth MUST cover:

  • @method: HTTP method
  • @authority: Target host
  • @path: Request path
  • signature-key: The Signature-Key header value

Resources MAY require additional components via additional_signature_components in metadata.

15.4. Signature Parameters

The Signature-Input header MUST include:

  • created: Signature creation timestamp (Unix time)

The created timestamp MUST NOT be more than 60 seconds in the past or future.

16. Request Verification

When a server (resource or auth server) receives a signed request, it MUST perform the following verification steps. Any failure MUST result in a 401 response with the appropriate error code.

16.1. HTTP Signature Verification

  1. Extract the Signature, Signature-Input, and Signature-Key headers. If any are missing, return invalid_signature.
  2. Verify that the Signature-Input covers the required components: @method, @authority, @path, and signature-key. If the resource requires additional components via additional_signature_components, verify those are covered as well.
  3. Verify the created parameter is present and within 60 seconds of the current time. Reject if outside this window.
  4. Obtain the public key from the Signature-Key header according to the scheme:

    • scheme=hwk: Use the inline public key.
    • scheme=jwks_uri: Fetch the JWKS from the specified URI and select the key matching the signature's keyid.
    • scheme=jwt: Extract the public key from the JWT's cnf claim (see JWT Verification below).
    • scheme=x509: Extract the public key from the certificate.
  5. Verify the HTTP Message Signature ([RFC9421]) using the obtained public key.

16.2. JWT Verification

When a request includes a JWT (agent token or auth token) via scheme=jwt, the server MUST verify the JWT per [RFC7515] and [RFC7519]:

  1. Decode the JWT header. Verify typ matches the expected token type (agent+jwt or auth+jwt).
  2. Verify the JWT signature using the issuer's public key, obtained by fetching the issuer's JWKS from jwks_uri in the issuer's metadata and selecting the key matching the JWT's kid header parameter. Keys are JSON Web Keys as defined in [RFC7517].
  3. Verify the exp claim is in the future. Verify the iat claim is not in the future.
  4. Key binding: Verify that the public key in the JWT's cnf claim ([RFC7800]) matches the key used to sign the HTTP request. This binds the JWT to the request signer.

16.2.1. Agent Token Verification

When verifying an agent token (typ: agent+jwt):

  1. Perform JWT Verification above using the agent server's JWKS (fetched from jwks_uri in /.well-known/aauth-agent.json at the iss URL).
  2. Verify iss is a valid HTTPS URL conforming to the Server Identifier requirements.
  3. Verify the cnf.jwk matches the key used to sign the HTTP request.
  4. If aud is present, verify that the server's own identifier is listed in the aud claim. If the server's identifier is not listed, reject the token.

16.2.2. Auth Token Verification

When verifying an auth token (typ: auth+jwt):

  1. Perform JWT Verification above using the auth server's JWKS (fetched from jwks_uri in /.well-known/aauth-issuer.json at the iss URL).
  2. Verify iss is a valid HTTPS URL conforming to the Server Identifier requirements.
  3. Verify aud matches the resource's own identifier (or the agent's identifier for self-access tokens).
  4. Verify agent matches the agent identifier from the request's signing context.
  5. Verify cnf.jwk matches the key used to sign the HTTP request.
  6. Verify that at least one of sub or scope is present.

16.2.3. Resource Token Verification

When an auth server receives a resource token (typ: resource+jwt) in a token request:

  1. Perform JWT Verification above using the resource's JWKS (fetched from jwks_uri in /.well-known/aauth-resource.json at the iss URL).
  2. Verify aud matches the auth server's own identifier.
  3. Verify agent matches the requesting agent's identifier.
  4. Verify agent_jkt ([RFC7638]) matches the JWK Thumbprint of the key used to sign the HTTP request.
  5. Verify exp is in the future.
  6. Verify jti has not been seen before (replay detection). The auth server SHOULD maintain a cache of seen jti values for the token's lifetime.
  7. If txn is present, carry it forward into the issued auth token.

17. Response Verification

Agents MUST verify responses from auth servers and resources to prevent token injection and confused deputy attacks.

17.1. Auth Token Response Verification

When an agent receives an auth token from an auth server (either as a direct grant or via polling):

  1. Verify the auth token JWT per the JWT Verification steps above, using the auth server's JWKS.
  2. Verify iss matches the auth server the agent sent the token request to.
  3. Verify aud matches the resource the agent intends to access (or the agent's own identifier for self-access tokens).
  4. Verify cnf.jwk matches the agent's own signing key.
  5. Verify agent matches the agent's own identifier.

17.2. Resource Challenge Verification

When an agent receives a 401 response with AAuth: require=auth-token:

  1. Extract the resource-token and auth-server parameters from the AAuth header.
  2. Decode the resource token JWT header and verify typ is resource+jwt.
  3. Verify the resource token JWT signature using the resource's JWKS (fetched from jwks_uri in /.well-known/aauth-resource.json).
  4. Verify iss matches the resource the agent sent the request to.
  5. Verify agent matches the agent's own identifier.
  6. Verify agent_jkt matches the JWK Thumbprint of the agent's signing key.
  7. Verify exp is in the future.

These checks prevent a malicious intermediary from substituting a different resource token or redirecting the agent to a different auth server.

18. Error Responses

AAuth defines error responses for both 401 authentication challenges and deferred response error codes. Token and signature errors use 401 with JSON error bodies. Deferred response errors use standard HTTP status codes with JSON error bodies as defined in the Deferred Responses section.

18.1. Error Response Format

{
  "error": "invalid_request",
  "error_description": "Human-readable description"
}

18.2. Authentication Error Codes

These errors are returned as 401 responses to API requests.

18.2.1. invalid_signature

The HTTP Message Signature is missing, malformed, or verification failed. When the signature is missing required components, the response SHOULD include required_components:

{
  "error": "invalid_signature",
  "error_description": "Signature missing required components",
  "required_components": ["@method", "@authority", "@path", "signature-key"]
}

18.2.2. invalid_agent_token

The agent token is missing, malformed, expired, or signature verification failed.

18.2.3. invalid_resource_token

The resource token is missing, malformed, expired, or signature verification failed.

18.2.4. invalid_auth_token

The auth token is missing, malformed, expired, or signature verification failed.

18.2.5. key_binding_failed

The key binding verification failed. The public key used to sign the request does not match the key bound in the token.

18.3. Token Endpoint Error Codes

Errors returned in response to the initial POST to the token endpoint:

Table 4
Error Status Meaning
invalid_request 400 Malformed JSON, missing required fields, or invalid parameter values
invalid_resource_token 400 Resource token is invalid, expired, or malformed
invalid_signature 401 HTTP signature verification failed
invalid_auth_token 400 Expired auth token presented for refresh is invalid or beyond the refresh window
server_error 500 Internal error

18.4. Polling Error Codes

Errors returned as terminal responses when polling a pending URL:

Table 5
Error Status Meaning
denied 403 User or approver explicitly denied the request
abandoned 403 Interaction code was used but the user did not complete the interaction
expired 408 Timed out — interaction code was never used
invalid_code 410 Interaction code not recognized or already consumed
server_error 500 Internal error

Agents MUST treat unknown error values as fatal.

19. Design Rationale

19.1. Why Standard HTTP Async Pattern

AAuth uses standard HTTP async semantics (202 Accepted, Location, Prefer: wait, Retry-After) rather than custom polling mechanisms. This pattern:

  • Applies uniformly to all endpoints: Token endpoint, resource endpoints, and any future endpoints use the same deferred response protocol without per-endpoint async documentation.
  • Aligns with RFC 7240: The Prefer: wait semantics negotiate connection hold duration between agent and server.
  • Enables transparent async upgrades: Resources that were synchronous can become async (requiring user interaction, long-running computation) without breaking existing agents.
  • Replaces OAuth device flow: The Location URL serves as the device code, Prefer: wait replaces the polling interval, and standard status codes replace custom error strings.
  • Supports headless agents: CLI tools, background services, and IoT devices can obtain authorization without hosting a redirect endpoint.
  • Enables long-running consent: Complex authorization decisions (enterprise approvals, multi-party consent) can take minutes or hours.
  • Enables clarification chat: The agent can respond to user questions during consent via the same polling mechanism.
  • Eliminates authorization code interception: There is no authorization code in the redirect URL to intercept or replay.

19.2. Why No Authorization Code

OAuth 2.0 uses an authorization code as an intermediary: the auth server redirects the user to the client with a code in the URL, and the client exchanges the code for tokens via a back-channel request. This two-step process was designed to prevent tokens from appearing in browser history and server logs. However, authorization codes introduce their own attack surface:

  • Code interception: Authorization codes pass through the user's browser via URL query parameters, making them vulnerable to interception by malicious browser extensions, open redirectors, or referrer leakage. PKCE mitigates but does not eliminate this risk.
  • Code replay: Without PKCE, intercepted codes can be replayed. With PKCE, the code is bound to a verifier, but the complexity of correct PKCE implementation has led to widespread deployment errors.
  • Redirect URI validation: The auth server must validate redirect URIs to prevent code delivery to attacker-controlled endpoints. This validation is a frequent source of security vulnerabilities.

AAuth eliminates authorization codes entirely. The user redirect carries only the callback URL (which the agent chose and may include its own state), which has no security value to an attacker — it cannot be exchanged for tokens. The auth token is delivered exclusively via polling on the pending URL, authenticated by the agent's HTTP Message Signature. This means:

  • No sensitive material passes through the user's browser
  • No redirect URI validation is needed for token security (callback URLs serve only UX purposes)
  • No PKCE-equivalent is needed since there is no code to protect
  • Token delivery is authenticated end-to-end between agent and auth server

19.3. Why HTTPSig on Every Request

AAuth requires HTTP Message Signatures on every request to the auth server and resources. This differs from OAuth 2.0 where client authentication is optional or uses separate mechanisms (client secrets, mTLS, DPoP).

  • Message integrity, not just token binding: HTTPSig covers the HTTP method, path, authority, and optionally body, providing tamper detection that DPoP and mTLS do not offer.
  • Survives proxies and CDNs: Unlike mTLS which terminates at the first TLS endpoint, HTTPSig signatures survive through proxies, load balancers, and CDNs.
  • No bearer tokens: Every request proves possession of the signing key. There are no bearer tokens to exfiltrate.
  • Consistent across all auth levels: The same signing mechanism works for pseudonym, identity, and auth-token requests.

19.4. Why HTTPS-Based Agent Identity

AAuth uses HTTPS URLs as agent identifiers rather than pre-registered client IDs. Agents publish metadata and JWKS at well-known endpoints.

  • Dynamic ecosystems without pre-registration: Agents can interact with any auth server or resource without prior registration, enabling open ecosystems like MCP.
  • Self-published metadata: Agent metadata (name, logo, callback URLs, policies) is published by the agent and discoverable by any party.
  • Works with ephemeral keys: Agent delegates use short-lived keys bound to the agent's stable HTTPS identity, enabling frequent key rotation without registration changes.

19.5. Why Interaction Codes Instead of Opaque Tokens

  • Human-enterable: Short alphanumeric codes (e.g., ABCD1234) can be typed, read aloud, or entered from a different device.
  • QR-friendly: Short codes produce simple QR codes that scan reliably.
  • Displayable: Codes fit on any screen, terminal, or notification without truncation.
  • Self-contained tokens would be too long: A token carrying cryptographic binding, expiry, and issuer information would be too long for manual entry or simple QR codes.

19.6. Why Pending URLs Instead of Tokens

  • Standard HTTP resource: The pending URL is a standard HTTP resource polled with GET. No custom token exchange endpoint is needed.
  • Supports repeated polling: Unlike OAuth's authorization code (presented once to exchange for tokens), the pending URL supports repeated polling and long-hold connections via Prefer: wait.
  • Enables clarification chat: The agent can POST clarification responses to the same URL during consent.
  • Server-controlled state: The agent treats the URL as opaque. The server may embed state in the URL path or use it as a reference to server-side state.

19.7. Why No Refresh Token

  • HTTP signatures prove identity on every request: The agent's signing key already proves it is the legitimate token holder. A separate refresh token would be redundant proof.
  • Expired auth token provides authorization context: The expired token carries the audience, scope, and user binding. The auth server can issue a new token from this context.
  • Simpler agent implementation: Agents store one token per resource, not two. No refresh token rotation or revocation logic is needed.

19.8. Why JSON Instead of Form-Encoded

  • Modern API convention: JSON is the standard format for modern APIs. Form encoding is an OAuth legacy from browser form POST origins.
  • Structured data: JSON naturally represents nested objects (e.g., token endpoint responses with multiple fields). Form encoding requires flattening.
  • Consistent across request and response: Both request bodies and response bodies use JSON, avoiding format asymmetry.

19.9. Why Callback URL Has No Security Role

  • Tokens never pass through the user's browser: The auth token is delivered exclusively via polling. The callback URL carries no sensitive material.
  • No redirect URI validation needed for security: Unlike OAuth's authorization code flow, there is no code in the redirect to protect. Callback validation is unnecessary.
  • Purely a UX optimization: The callback wakes the agent up immediately rather than waiting for the next poll interval. If an attacker redirects the callback, the agent simply polls sooner — no tokens are exposed.

19.10. Why Separate Approval and Interaction

  • Unambiguous agent action: require=interaction means the agent must facilitate a redirect with the interaction code. require=approval means the AS is handling approval directly — the agent just polls.
  • Different user experiences: Interaction requires the agent to present a code or redirect a user. Approval may use push notifications, existing sessions, or email — none requiring agent involvement.
  • Prevents unnecessary UX: Without distinct values, agents would not know whether to prompt the user or wait silently.

19.11. Why Restrict Interaction Code Character Set

Interaction codes are restricted to unreserved URI characters ([RFC3986] Section 2.3: A-Z a-z 0-9 - . _ ~). Unreserved characters do not require percent-encoding in URI query parameters, eliminating double-encoding, missing encoding, and inconsistent encoding across implementations.

20. Security Considerations

20.1. Proof-of-Possession

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 cnf claim.

20.2. HTTP Message Signature Security

HTTP Message Signatures provide:

  1. Request Integrity: The signature covers HTTP method, target URI, and headers
  2. Replay Protection: The created timestamp limits signature validity
  3. Key Binding: Signatures are bound to specific keys via Signature-Key

20.3. Token Security

  • Agent tokens bind delegate keys to agent identity
  • Resource tokens bind access requests to resource identity, preventing confused deputy attacks
  • Auth tokens bind authorization grants to agent keys

20.4. Interaction Code Security

  • Interaction code values MUST be single-use, time-limited, and bound to the pending request
  • Callback URLs are agent-specified; agents SHOULD include unguessable state values to prevent CSRF

20.5. Pending URL Security

  • Pending URLs (Location values in 202 responses) MUST be unguessable and SHOULD have limited lifetime
  • Pending URLs MUST be on the same origin as the server that issued them
  • Servers MUST verify the agent's identity on every GET poll to the pending URL
  • Once a terminal response is returned, the pending URL MUST return 404 on subsequent requests

20.6. Clarification Chat Security

  • Auth servers MUST enforce a maximum number of clarification rounds to prevent abuse
  • Auth servers SHOULD enforce a timeout on clarification exchanges
  • Clarification responses from agents are untrusted input and MUST be sanitized before display to users

20.7. Auth Server Discovery

Resources include the auth-server parameter in their AAuth response header when returning a resource token. The agent MUST use the auth server URL from the resource's challenge — the resource determines which auth server to use for its tokens.

An agent MUST NOT substitute a different auth server than the one specified by the resource. Auth servers MUST verify that the resource token's aud matches their own identifier.

20.8. JWKS Caching

Servers that fetch JWKS documents for signature verification SHOULD cache the results with a TTL appropriate to their risk tolerance (recommended: 5 minutes for auth servers, 60 minutes for resources). Servers SHOULD support standard HTTP caching headers (Cache-Control, Expires) on JWKS responses.

When signature verification fails due to an unknown kid, the server SHOULD re-fetch the JWKS once before returning an error, to handle key rotation.

20.9. Call Chaining Identity

When a resource acts as an agent in call chaining, it uses its own signing key and presents its own credentials to the downstream resource. The downstream resource sees Resource 1 as the requesting agent. Resource 1 MUST publish agent metadata (/.well-known/aauth-agent.json) so that downstream resources and auth servers can verify its identity.

The upstream_token parameter in the token request allows the downstream auth server to verify the authorization chain — it can confirm that Resource 1 was authorized by the original user to access the upstream resource.

20.10. Token Revocation

This specification does not define a token revocation mechanism. Auth tokens are short-lived and bound to specific signing keys, limiting the window of exposure. Auth servers SHOULD issue auth tokens with the shortest practical lifetime. When a resource detects misuse, it can reject the token and require re-authorization.

Auth servers MAY implement revocation by maintaining a deny list of jti values. Resources can check revocation by querying the auth server, though this adds latency to every request. A future specification may define a standardized revocation mechanism.

20.11. Replay Protection

The created timestamp in HTTP Message Signatures limits signature validity to a 60-second window, providing basic replay protection. Servers MAY maintain a cache of recently seen signatures to detect replays within this window.

Resource tokens include a jti claim for replay detection at the auth server. Auth servers SHOULD maintain a cache of seen jti values for at least the token's lifetime to prevent resource token replay.

21. IANA Considerations

21.1. Well-Known URI Registrations

This specification registers the following Well-Known URIs:

  • aauth-agent.json: Agent server metadata
  • aauth-issuer.json: Auth server metadata
  • aauth-resource.json: Resource metadata

21.2. Media Type Registrations

This specification registers the following media types:

  • application/agent+jwt: Agent token
  • application/auth+jwt: Auth token
  • application/resource+jwt: Resource token

21.3. HTTP Header Field Registrations

This specification registers the following HTTP header:

  • AAuth: Authentication, authorization, and interaction requirements

22. References

22.1. Normative References

[I-D.hardt-httpbis-signature-key]
Hardt, D. and T. Meunier, "HTTP Signature-Key Header", Work in Progress, Internet-Draft, draft-hardt-httpbis-signature-key-01, , <https://datatracker.ietf.org/doc/html/draft-hardt-httpbis-signature-key-01>.
[RFC3986]
Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, , <https://www.rfc-editor.org/info/rfc3986>.
[RFC5890]
Klensin, J., "Internationalized Domain Names for Applications (IDNA): Definitions and Document Framework", RFC 5890, DOI 10.17487/RFC5890, , <https://www.rfc-editor.org/info/rfc5890>.
[RFC6749]
Hardt, D., Ed., "The OAuth 2.0 Authorization Framework", RFC 6749, DOI 10.17487/RFC6749, , <https://www.rfc-editor.org/info/rfc6749>.
[RFC7240]
Snell, J., "Prefer Header for HTTP", RFC 7240, DOI 10.17487/RFC7240, , <https://www.rfc-editor.org/info/rfc7240>.
[RFC7515]
Jones, M., Bradley, J., and N. Sakimura, "JSON Web Signature (JWS)", RFC 7515, DOI 10.17487/RFC7515, , <https://www.rfc-editor.org/info/rfc7515>.
[RFC7517]
Jones, M., "JSON Web Key (JWK)", RFC 7517, DOI 10.17487/RFC7517, , <https://www.rfc-editor.org/info/rfc7517>.
[RFC7519]
Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token (JWT)", RFC 7519, DOI 10.17487/RFC7519, , <https://www.rfc-editor.org/info/rfc7519>.
[RFC7638]
Jones, M. and N. Sakimura, "JSON Web Key (JWK) Thumbprint", RFC 7638, DOI 10.17487/RFC7638, , <https://www.rfc-editor.org/info/rfc7638>.
[RFC7800]
Jones, M., Bradley, J., and H. Tschofenig, "Proof-of-Possession Key Semantics for JSON Web Tokens (JWTs)", RFC 7800, DOI 10.17487/RFC7800, , <https://www.rfc-editor.org/info/rfc7800>.
[RFC8615]
Nottingham, M., "Well-Known Uniform Resource Identifiers (URIs)", RFC 8615, DOI 10.17487/RFC8615, , <https://www.rfc-editor.org/info/rfc8615>.
[RFC8941]
Nottingham, M. and P. Kamp, "Structured Field Values for HTTP", RFC 8941, DOI 10.17487/RFC8941, , <https://www.rfc-editor.org/info/rfc8941>.
[RFC9110]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, , <https://www.rfc-editor.org/info/rfc9110>.
[RFC9421]
Backman, A., Ed., Richer, J., Ed., and M. Sporny, "HTTP Message Signatures", RFC 9421, DOI 10.17487/RFC9421, , <https://www.rfc-editor.org/info/rfc9421>.

22.2. Informative References

[OpenID.Core]
Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and C. Mortimore, "OpenID Connect Core 1.0", , <https://openid.net/specs/openid-connect-core-1_0.html>.
[OpenID.Enterprise]
Hardt, D. and K. McGuinness, "OpenID Connect Enterprise Extensions 1.0", , <https://openid.net/specs/openid-connect-enterprise-extensions-1_0.html>.
[RFC7591]
Richer, J., Ed., Jones, M., Bradley, J., Machulak, M., and P. Hunt, "OAuth 2.0 Dynamic Client Registration Protocol", RFC 7591, DOI 10.17487/RFC7591, , <https://www.rfc-editor.org/info/rfc7591>.

Appendix A. Agent Token Acquisition Patterns

This appendix describes common patterns for how agent delegates obtain agent tokens from their agent server. The specific mechanism is out of scope for this specification.

A.1. Server Workloads

Server workloads include containerized services, microservices, and serverless functions. These workloads prove identity using platform attestation.

SPIFFE-based: The workload obtains a SPIFFE SVID from the Workload API, generates an ephemeral key pair, and presents the SVID to the agent server via mTLS. The agent server issues an agent token with sub set to the SPIFFE ID.

WIMSE-based: The workload authenticates using platform credentials (cloud provider instance identity, Kubernetes service account tokens). The agent server evaluates delegation policies before issuing tokens.

A.2. Mobile Applications

Mobile apps prove legitimate installation using platform attestation APIs (iOS App Attest, Android Play Integrity API). Each installation generates a persistent ID and key pair. The agent server validates the attestation and issues an agent token with an installation-level sub.

A.3. Desktop and CLI Applications

Desktop and CLI tools use platform vaults (macOS Keychain, Windows TPM, Linux Secret Service) or ephemeral keys. After user authentication, the agent server issues tokens with an installation-level sub that persists across key rotations.

A.4. Browser-Based Applications

Browser-based applications generate ephemeral key pairs using the Web Crypto API. The web server acts as agent server and issues agent tokens to the browser session. Each session has a unique sub for tracking.

Appendix B. Acknowledgments

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.

Author's Address

Dick Hardt
Hellō