> ## Documentation Index
> Fetch the complete documentation index at: https://docs.afauth.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Conformance

> Conformance criteria for agent and service roles.

<Info>This page is auto-synced from [`AFAuthHQ/spec/spec/conformance.md`](https://github.com/AFAuthHQ/spec/blob/main/spec/conformance.md). Do not edit here.</Info>
**Status:** Stable alongside `core.md`. The §C.1 through §C.6 test-vector corpus and the executable harness at [`../harness/run.js`](https://github.com/AFAuthHQ/spec/blob/main/harness/run.js) ship in this repository; an implementation that passes every committed vector through its own verifier may claim v0.1 conformance for its declared role.

This document describes what an AFAuth implementation must support to call itself "AFAuth-conformant." It is the authoritative reference for that claim; the protocol specification ([`core.md`](/spec/core)) provides the underlying normative requirements.

## Scope

An AFAuth-conformant implementation is either an **agent** that signs requests according to the protocol, or a **service** that verifies them and operates the account lifecycle. Conformance is asserted separately for each role.

This document does NOT specify:

* What operations an agent may perform at any given account state beyond the §7.5 owner-binding floor (out of scope per §1.3).
* The user interface of the claim ceremony (service responsibility per §12.3).
* The treatment of pre-claim account state at claim time (service responsibility per §12.7).

## Service conformance (planned probes)

A conforming service MUST:

1. **Discovery.** Serve a valid `/.well-known/afauth` document per the schema, including all `required` endpoints (`accounts`, `owner_invitation`, `claim_page`, `claim_completion`).
2. **Signature verification.** Accept the §5.2 covered components and parameters; reject requests with extra or missing components; honour `created` and `expires`; maintain a `(keyid, nonce)` replay set covering at least `expires - created + skew_tolerance`.
3. **State machine.** Implement all and only the transitions in Appendix A. In particular, transition `UNCLAIMED → INVITED → CLAIMED` only via the §7 flow; never bind an owner whose authenticated identity does not satisfy the match relation against `pending_recipient` for its registered type (§7.4, §7.7).
4. **Two-step verify (§7.1).** Reject any flow in which the agent's signature alone binds ownership.
5. **Owner-binding floor (§7.5).** Reject agent-signed owner-binding operations post-claim with `403 Forbidden` and `owner_binding_blocked`.
6. **Invitation atomicity (§7.3).** At most one pending invitation per account at any time; atomic replacement; invalidated tokens MUST fail with `410 Gone`.
7. **`attested_only` honouring (§9, §6.3).** Services declaring `unclaimed_mode = "attested_only"` MUST reject implicit signup lacking attestation with `attestation_required`, without creating the account.
8. **Error codes (§11).** Use the reserved codes for the conditions they describe.
9. **Recipient types (§7.7).** Accept at minimum the `email` recipient type. Declare any additional supported types in `recipient_types` of the discovery doc. Reject unsupported types in invitation requests with `400 Bad Request` and `unsupported_recipient_type`.
10. **Owner re-key & revoke (§8.2, §8.4).** A service that advertises `key_rekey` / `key_revocation` MUST gate them on a fresh owner-authenticated session (§7.5) — never the agent signature — and MUST verify the session owns the target account: reject a stale session with `owner_session_too_stale`, a non-owner with `owner_authentication_required` (and no session with `401`), and a non-`CLAIMED` target with `not_claimed`. After revoke — and, for the old DID, after re-key — a request signed by the retired key MUST fail with `401 revoked_key`.
11. **Attested sessions (§10.7).** A service that advertises `attested_session` MUST treat a presented attestation as valid only until its `exp` (strict mode) — or, in extended mode, until a service-chosen window `T` refreshed on each presentation — and MUST challenge a request from an established account whose freshness window has lapsed with `401 attestation_required` rather than serving it on the agent signature alone. It MUST reject an already-expired attestation presented as a refresh (§10.2).

A conforming service SHOULD additionally:

12. **Authentication challenge (§5.7).** Emit a `WWW-Authenticate: AFAuth …` challenge on `401 Unauthorized`, carrying at least `discovery`, and — on `attestation_required` / `invalid_attestation` — `attestors`. Emission is RECOMMENDED, not required. When emitted: the challenge MUST be syntactically valid per \[RFC9110]; its `error`, if present, MUST equal the body's `error.code` and MUST be set only when the request attempted AFAuth (carried `Signature-Input` or `AFAuth-Attestation`) — otherwise the challenge is a bare advertisement with no `error`; and on a resource that also accepts other schemes the AFAuth challenge MUST be one of possibly several `WWW-Authenticate` challenges, never suppressing or reordering another scheme's.

## Agent conformance (planned probes)

A conforming agent MUST:

1. **Discovery.** Fetch and honour `/.well-known/afauth` before signup; respect the declared `signature_algorithms` and `billing.unclaimed_mode`.
2. **Identity.** Generate a valid `did:key` account identifier per §3.1.1, including canonical multibase/multicodec encoding.
3. **Signing.** Produce signatures with all §5.2 covered components and parameters; bound `expires - created` ≤ 300 seconds; use a fresh nonce per request.
4. **Key handling.** Store private keys per §3.2 / §12.1 recommendations; rotate per §8.
5. **Claim flow.** Initiate the two-step invitation per §7.2; treat `410 Gone` on an invitation as a normal expiry condition.
6. **Attestation refresh (§10.7).** On `401 attestation_required` from a service with which it has an established account, an agent SHOULD obtain a fresh attestation (§10) and retry the request. It MUST NOT treat a transient mint failure as terminal, and MUST stop and surface a revoked or paused binding (a refused mint) to the operator rather than retrying indefinitely.

A conforming agent SHOULD additionally:

7. **Authentication challenge (§5.7).** Read the `WWW-Authenticate: AFAuth …` challenge on a `401` to bootstrap discovery (`discovery`) and route recovery (`error`, and `attestors` for attestation failures). It MUST NOT require the challenge to be present — when absent, fall back to fetching `/.well-known/afauth` by convention (§4) — and MUST ignore `auth-param`s it does not recognize.

## Versioning

This document tracks the protocol version it describes. Future revisions will use additive probes for non-breaking protocol changes and a new major version for breaking changes.

## Test vectors and harness

The Appendix C corpus ships under [`../vectors/`](https://github.com/AFAuthHQ/spec/tree/main/vectors/):

* **§C.1, §C.2** — [`vectors/signatures/`](https://github.com/AFAuthHQ/spec/tree/main/vectors/signatures/): canonical input + reference signatures.
* **§C.3** — [`vectors/discovery/`](https://github.com/AFAuthHQ/spec/tree/main/vectors/discovery/): well-formed, forward-compatible, and malformed discovery documents.
* **§C.4** — [`vectors/recipients/`](https://github.com/AFAuthHQ/spec/tree/main/vectors/recipients/): per-type normalisation rules with canonical forms.
* **§C.5** — [`vectors/errors/`](https://github.com/AFAuthHQ/spec/tree/main/vectors/errors/): one envelope fixture per §11.3 reserved code.
* **§C.6** — [`vectors/replay-window/`](https://github.com/AFAuthHQ/spec/tree/main/vectors/replay-window/): expired, future-dated, replay-invariant, and cross-keyid sequences.
* **§C.7** — [`vectors/trust-attestation/`](https://github.com/AFAuthHQ/spec/tree/main/vectors/trust-attestation/): `afauth-trust` attestation JWTs — well-formed, runtime-only (no `sub_h`), and malformed `sub_h` cases (§10). Applies only to implementations that consume attestations.

The executable harness at [`../harness/run.js`](https://github.com/AFAuthHQ/spec/blob/main/harness/run.js) runs every fixture against a reference verifier and exits non-zero on any failure. It exports its primitives (`buildCanonicalInput`, `verifySignature`, `checkDiscoveryDocument`, `normaliseRecipient`, …) so independent implementations can reuse them. Contributions of additional vectors are welcome via the proposals process (see [`../proposals/`](https://github.com/AFAuthHQ/spec/blob/main/proposals/README.md)).
