<?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-headers-00" submissionType="IETF" category="std" xml:lang="en" indexInclude="true">

<front>
<title abbrev="AAuth-Headers">HTTP AAuth Headers</title><seriesInfo value="draft-hardt-aauth-headers-00" 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>http</keyword>
<keyword>signatures</keyword>

<abstract>
<t>This document defines two HTTP response headers — AAuth-Requirement and AAuth-Error — and profiles HTTP Message Signatures (<xref target="RFC9421"/>) for request authentication, with keying material conveyed via the Signature-Key header (<xref target="I-D.hardt-httpbis-signature-key"/>). A server uses AAuth-Requirement to require pseudonymous or verified agent identity, to request user interaction, or to signal that approval is pending. AAuth-Error conveys structured error information. Both headers use extensible registries for their values.</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>
<t>Modern distributed systems need a standard way for servers to communicate requirements to agents and for agents to present cryptographic identity. The existing HTTP <tt>WWW-Authenticate</tt> header (<xref target="RFC9110"/>, Section 11.6.1) is limited to a fixed set of authentication schemes, cannot express progressive requirements, and cannot appear in <tt>202 Accepted</tt> responses. The AAuth-Requirement header provides an extensible mechanism for progressive requirements — from pseudonymous access and verified identity to user interaction and deferred approval.</t>
<t>This specification defines:</t>

<ul spacing="compact">
<li>The <tt>AAuth-Requirement</tt> HTTP response header with an extensible requirement level registry</li>
<li>Four requirement levels: <tt>pseudonym</tt>, <tt>identity</tt>, <tt>interaction</tt>, and <tt>approval</tt></li>
<li>A profile of HTTP Message Signatures (<xref target="RFC9421"/>) for request authentication, specifying required covered components, signature parameters, and keying material via the <tt>Signature-Key</tt> header (<xref target="I-D.hardt-httpbis-signature-key"/>)</li>
<li>The <tt>AAuth-Error</tt> HTTP response header with an extensible error code registry</li>
</ul>
</section>

<section anchor="conventions-and-definitions"><name>Conventions and Definitions</name>
<t>{::boilerplate bcp14-tagged}</t>
<t>All HTTP requests and responses in AAuth MUST use HTTPS (HTTP over TLS (<xref target="RFC8446"/>)). Any reference to "HTTP" in this document implies HTTPS unless explicitly noted otherwise.</t>
</section>

<section anchor="terminology"><name>Terminology</name>

<ul spacing="compact">
<li><strong>Agent</strong>: An HTTP client (<xref target="RFC9110"/>, Section 3.5) that signs its requests. In AAuth, agents have cryptographic identity.</li>
<li><strong>Server</strong>: An HTTP origin server (<xref target="RFC9110"/>, Section 3.6) that communicates requirements via the <tt>AAuth-Requirement</tt> header.</li>
</ul>
</section>

<section anchor="aauth-requirement-http-response-header"><name>AAuth-Requirement HTTP Response Header</name>
<t>Servers use the <tt>AAuth-Requirement</tt> response header to indicate 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 authentication or 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 authentication and payment. The <tt>AAuth-Requirement</tt> conveys the authentication requirement; the payment requirement is conveyed by a separate mechanism such as x402 <xref target="x402"/> or the Micropayment Protocol (MPP) (<xref target="I-D.ryan-httpauth-payment"/>).</t>

<section anchor="header-structure"><name>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 level.</li>
</ul>
<t>Additional members are defined per requirement level by the specification that registers the level. Recipients MUST ignore unknown members.</t>
<t>Example:</t>

<sourcecode type="http"><![CDATA[AAuth-Requirement: requirement=pseudonym
]]></sourcecode>
</section>

<section anchor="requirement-levels"><name>Requirement Levels</name>
<t>The <tt>requirement</tt> value is an extension point. This document defines four levels:</t>
<table>
<thead>
<tr>
<th>Level</th>
<th>Status Code</th>
<th>Meaning</th>
</tr>
</thead>

<tbody>
<tr>
<td><tt>pseudonym</tt></td>
<td><tt>401</tt></td>
<td>Signed request proving key possession</td>
</tr>

<tr>
<td><tt>identity</tt></td>
<td><tt>401</tt></td>
<td>Verified agent identity</td>
</tr>

<tr>
<td><tt>interaction</tt></td>
<td><tt>202</tt></td>
<td>User action required at an interaction endpoint</td>
</tr>

<tr>
<td><tt>approval</tt></td>
<td><tt>202</tt></td>
<td>Approval pending, poll for result</td>
</tr>
</tbody>
</table><t>The AAuth Protocol specification (draft-hardt-aauth-protocol) registers additional levels (e.g., <tt>auth-token</tt>).</t>
</section>

<section anchor="pseudonym-required"><name>Pseudonym Required</name>
<t>When a server requires a signed request:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 401 Unauthorized
AAuth-Requirement: requirement=pseudonym
]]></sourcecode>
<t>The agent retries with an HTTP Message Signature using a pseudonymous Signature-Key scheme ({{keying-material}}). The server can track the agent by JWK Thumbprint (<xref target="RFC7638"/>) without knowing its identity.</t>

<sourcecode type="ascii-art"><![CDATA[Agent                                          Server
  |                                               |
  |  unsigned request                             |
  |---------------------------------------------->|
  |                                               |
  |  401 Unauthorized                             |
  |  AAuth-Requirement: requirement=pseudonym           |
  |<----------------------------------------------|
  |                                               |
  |  HTTPSig request                              |
  |  (pseudonymous key)                           |
  |---------------------------------------------->|
  |                                               |  verify signature,
  |                                               |  track by key
  |                                               |  thumbprint
  |                                               |
  |  200 OK                                       |
  |<----------------------------------------------|
  |                                               |
]]></sourcecode>
<t>If the agent already knows the server requires pseudonymous access (from a previous interaction or metadata), it MAY sign the initial request directly without waiting for a <tt>401</tt> challenge.</t>
<t><strong>Use cases:</strong> Rate limiting anonymous requests, tracking repeat visitors by key thumbprint, spam prevention without requiring verified identity, hardware-backed pseudonymous identity.</t>
</section>

<section anchor="identity-required"><name>Identity Required</name>
<t>When a server requires verified agent identity:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 401 Unauthorized
AAuth-Requirement: requirement=identity
]]></sourcecode>
<t>The agent retries with a signed request using an identity Signature-Key scheme ({{keying-material}}).</t>

<sourcecode type="ascii-art"><![CDATA[Agent                                          Server
  |                                               |
  |  HTTPSig request                              |
  |---------------------------------------------->|
  |                                               |
  |  401 Unauthorized                             |
  |  AAuth-Requirement: requirement=identity            |
  |<----------------------------------------------|
  |                                               |
  |  HTTPSig request                              |
  |  (verifiable identity)                        |
  |---------------------------------------------->|
  |                                               |  verify agent
  |                                               |  identity,
  |                                               |  apply policy
  |                                               |
  |  200 OK                                       |
  |<----------------------------------------------|
  |                                               |
]]></sourcecode>
<t>If the agent already knows the server requires agent identity, it MAY present its identity on the initial request without waiting for a <tt>401</tt> challenge.</t>
<t><strong>Use cases:</strong> API access policies based on known agents, webhook signature verification, allowlisting trusted agents for elevated rate limits.</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="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> ({{error-codes}}).</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-resource"><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>AAuth-Error</tt> header ({{error-codes}}).</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 {{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 60 seconds of the server's current time. 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="aauth-error-http-response-header"><name>AAuth-Error HTTP Response Header</name>
<t>When a server rejects a request that includes AAuth signature headers (<tt>Signature</tt>, <tt>Signature-Input</tt>, and <tt>Signature-Key</tt>), the <tt>401</tt> response MUST include the <tt>AAuth-Error</tt> header.</t>

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

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

<sourcecode type="http"><![CDATA[AAuth-Error: error=unsupported_algorithm,
    supported_algorithms=("EdDSA" "ES256")
]]></sourcecode>
<t>The response body is OPTIONAL and MAY contain a human-readable description in any content type. The agent MUST NOT depend on the response body for error handling — all machine-readable error information is in the header.</t>
</section>

<section anchor="error-codes"><name>Error Codes</name>

<section anchor="invalid-request"><name>invalid_request</name>
<t>The request is malformed or missing required information unrelated to signature verification — such as missing query parameters or an unsupported content type.</t>

<sourcecode type="http"><![CDATA[AAuth-Error: error=invalid_request
]]></sourcecode>
</section>

<section anchor="invalid-input"><name>invalid_input</name>
<t>The Signature-Input is missing required covered components. The response SHOULD include a <tt>required_input</tt> member listing the components the server requires (see {{covered-components}} for the base set):</t>

<sourcecode type="http"><![CDATA[AAuth-Error: error=invalid_input,
    required_input=("@method" "@authority" "@path"
    "signature-key" "content-digest")
]]></sourcecode>
</section>

<section anchor="invalid-signature"><name>invalid_signature</name>
<t>The HTTP Message Signature is missing, malformed, or cryptographic verification failed. This includes missing <tt>Signature</tt>, <tt>Signature-Input</tt>, or <tt>Signature-Key</tt> headers, an expired <tt>created</tt> timestamp, or a signature that does not verify.</t>

<sourcecode type="http"><![CDATA[AAuth-Error: error=invalid_signature
]]></sourcecode>
</section>

<section anchor="unsupported-algorithm"><name>unsupported_algorithm</name>
<t>The signing algorithm used by the agent is not supported by the server. The response MUST include a <tt>supported_algorithms</tt> member:</t>

<sourcecode type="http"><![CDATA[AAuth-Error: error=unsupported_algorithm,
    supported_algorithms=("EdDSA" "ES256")
]]></sourcecode>
</section>

<section anchor="invalid-key"><name>invalid_key</name>
<t>The public key in <tt>Signature-Key</tt> could not be parsed, is expired, or does not meet the server's trust requirements.</t>

<sourcecode type="http"><![CDATA[AAuth-Error: error=invalid_key
]]></sourcecode>
</section>

<section anchor="unknown-key"><name>unknown_key</name>
<t>The public key from <tt>Signature-Key</tt> does not match any key at the agent's <tt>jwks_uri</tt> (applicable when the agent uses <tt>scheme=jwks_uri</tt> for verified identity; see {{keying-material}}). The server SHOULD re-fetch the JWKS once before returning this error, to handle key rotation.</t>

<sourcecode type="http"><![CDATA[AAuth-Error: error=unknown_key
]]></sourcecode>
</section>

<section anchor="invalid-jwt"><name>invalid_jwt</name>
<t>The JWT in the <tt>Signature-Key</tt> header (when using <tt>scheme=jwt</tt> or <tt>scheme=jkt-jwt</tt>) is malformed or its signature verification failed.</t>

<sourcecode type="http"><![CDATA[AAuth-Error: error=invalid_jwt
]]></sourcecode>
</section>

<section anchor="expired-jwt"><name>expired_jwt</name>
<t>The JWT in the <tt>Signature-Key</tt> header (when using <tt>scheme=jwt</tt> or <tt>scheme=jkt-jwt</tt>) has expired (<tt>exp</tt> claim is in the past).</t>

<sourcecode type="http"><![CDATA[AAuth-Error: error=expired_jwt
]]></sourcecode>
</section>
</section>

<section anchor="access-denied"><name>Access Denied</name>
<t>When the server successfully verifies the agent's signature and identity but denies access based on policy (e.g., the agent is not authorized for this resource), the server returns <tt>403 Forbidden</tt>. This is not an AAuth error — the authentication succeeded but authorization was denied. The response MUST NOT include an <tt>AAuth-Requirement</tt> or <tt>AAuth-Error</tt> header.</t>
</section>
</section>

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

<section anchor="key-thumbprint-tracking"><name>Key Thumbprint Tracking</name>
<t>When an agent uses <tt>scheme=hwk</tt> (pseudonymous access), the server can track the agent across requests by JWK Thumbprint (<xref target="RFC7638"/>). If the agent uses the same key across multiple servers, those servers could correlate the agent's activity. Agents MUST use distinct keys for distinct servers to prevent cross-server correlation of pseudonymous identity.</t>
</section>

<section anchor="agent-identity-disclosure"><name>Agent Identity Disclosure</name>
<t>When an agent presents its identity via <tt>scheme=jwks_uri</tt> or <tt>scheme=jwt</tt>, the server learns the agent's HTTPS URL. This reveals which software is making the request. Servers SHOULD NOT disclose agent identity information to third parties without the agent operator's consent.</t>
</section>

<section anchor="jwks-fetch-side-channel"><name>JWKS Fetch Side Channel</name>
<t>When a server fetches an agent's JWKS from <tt>jwks_uri</tt> to verify a signature, the fetch itself reveals to the agent's JWKS host that someone is verifying signatures for that agent.</t>
</section>
</section>

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

<section anchor="http-message-signature-security"><name>HTTP Message Signature Security</name>
<t>HTTP Message Signatures provide:</t>

<ol spacing="compact">
<li><strong>Request Integrity</strong>: The signature covers HTTP method, target URI, and headers</li>
<li><strong>Replay Protection</strong>: The <tt>created</tt> timestamp limits signature validity</li>
<li><strong>Key Binding</strong>: Signatures are bound to specific keys via <tt>Signature-Key</tt></li>
</ol>
</section>

<section anchor="replay-protection"><name>Replay Protection</name>
<t>The 60-second validity window on the <tt>created</tt> timestamp (see {{verification-resource}}) limits the useful lifetime of a captured signature. The 60-second value balances clock-skew tolerance (NTP-synchronized hosts typically drift less than 10 seconds) against replay exposure — a shorter window would reject legitimate requests from hosts with modest clock drift, while a longer window would widen the replay attack surface.</t>
<t>Within that window, resources MUST maintain a cache of recently seen (key thumbprint, <tt>created</tt>) pairs and reject duplicate combinations. Without this cache, an attacker who captures a signed request can replay it within the validity window.</t>
</section>

<section anchor="jwks-caching"><name>JWKS Caching</name>
<t>Resources 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). JWKS endpoints SHOULD support standard HTTP caching headers (<tt>Cache-Control</tt>, <tt>Expires</tt>) per (<xref target="RFC9111"/>).</t>
<t>When signature verification fails due to an unknown key, the server SHOULD re-fetch the JWKS once before returning an <tt>unknown_key</tt> error, to handle key rotation.</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 entry in the "Hypertext Transfer Protocol (HTTP) Field Name Registry" (<xref target="RFC9110"/>, Section 16.3.1):</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</t>
</li>
<li><t>Header Field Name: <tt>AAuth-Error</tt></t>
</li>
<li><t>Status: permanent</t>
</li>
<li><t>Structured Type: Dictionary</t>
</li>
<li><t>Reference: This document</t>
</li>
</ul>
</section>

<section anchor="aauth-requirement-level-registry"><name>AAuth Requirement Level Registry</name>
<t>This specification establishes the AAuth Requirement Level Registry. The initial contents are:</t>
<table>
<thead>
<tr>
<th>Value</th>
<th>Reference</th>
</tr>
</thead>

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

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

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

<tr>
<td><tt>approval</tt></td>
<td>This document</td>
</tr>
</tbody>
</table><t>New values may be registered following the Specification Required policy (<xref target="RFC8126"/>).</t>
</section>

<section anchor="aauth-error-code-registry"><name>AAuth Error Code Registry</name>
<t>This specification establishes the AAuth Error Code Registry. The initial contents are:</t>
<table>
<thead>
<tr>
<th>Value</th>
<th>Reference</th>
</tr>
</thead>

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

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

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

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

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

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

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

<tr>
<td><tt>expired_jwt</tt></td>
<td>This document</td>
</tr>
</tbody>
</table><t>New values may be registered following the Specification Required policy (<xref target="RFC8126"/>).</t>
</section>
</section>

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

<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>AAuth-Requirement coexists with <tt>WWW-Authenticate</tt>. A <tt>401</tt> response MAY include both headers, and the client uses whichever it understands:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
AAuth-Requirement: requirement=identity
]]></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>AAuth-Requirement</tt> for authentication or authorization:</t>

<sourcecode type="http"><![CDATA[HTTP/1.1 402 Payment Required
WWW-Authenticate: Payment id="x7Tg2pLq", method="example",
    request="eyJhbW91bnQiOiIxMDAw..."
AAuth-Requirement: requirement=pseudonym
]]></sourcecode>
</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 at the time of writing:</t>

<ul>
<li><t><strong>@aauth npm packages</strong> (<eref target="https://www.npmjs.com/org/aauth):">https://www.npmjs.com/org/aauth):</eref> JavaScript/TypeScript libraries implementing HTTP Message Signatures and AAuth-Requirement processing for agents and servers.</t>
</li>
<li><t><strong>aauth-implementation</strong> (<eref target="https://github.com/christian-posta/aauth-implementation):">https://github.com/christian-posta/aauth-implementation):</eref> Python library implementing HTTP Message Signatures (RFC 9421), AAuth request signing/verification, and Signature-Key header support. Author: Christian Posta.</t>
</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 spacing="compact">
<li><t>draft-hardt-aauth-headers-00</t>

<ul spacing="compact">
<li>Initial submission, renamed from draft-hardt-aauth-header</li>
<li>Added AAuth-Error header with extensible error code registry</li>
<li>Added <tt>interaction</tt> and <tt>approval</tt> requirement levels</li>
<li>Added <tt>url</tt> parameter to interaction for self-contained challenge</li>
<li>Renamed terminology from "resource" to "server"</li>
</ul></li>
</ul>
</section>

<section anchor="acknowledgments"><name>Acknowledgments</name>
<t>TBD</t>
</section>

</middle>

<back>
<references><name>References</name>
<references><name>Normative References</name>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.hardt-httpbis-signature-key.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ryan-httpauth-payment.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.7517.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.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.8446.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.9110.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9421.xml"/>
</references>
<references><name>Informative References</name>
<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.7942.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9111.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9530.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>

</back>

</rfc>
