attested_only service that checks attestation once at signup and thereafter trusts the agent’s signature has a blind spot (§8.5): an attestor-side revoke or disable never reaches it. The stolen key keeps working until that service’s own revocation list catches it.
§10.7 closes that gap without paying the cost of re-checking attestation on every request. The service keeps a currently-valid attestation on file per account — an attested session — and challenges with 401 attestation_required once it lapses. The agent answers by minting a fresh attestation and retrying. Revoke the binding at the attestor and the agent can no longer mint, so every attested-session service drops the account within its freshness window.
It’s the OAuth refresh pattern applied to attestation: the agent’s live binding at the attestor is the refresh grant — it re-mints by signing /v1/token with its account key — the attestation is the short-lived access token, and revoking the binding kills the access within the access token’s lifetime.
Opt-in, for
attested_only services (the defineService default). Advertise support with the attested_session feature in your discovery document. Services that don’t opt in keep the signup-only behaviour.Service side — gate on freshness
ConfigureattestedSession on your Server (alongside the attestor you already use at signup) and call verifyAttested on your own authenticated routes:
verifyAttested:
- verifies the RFC 9421 signature (the per-request authenticator);
- if the request carries an
AFAuth-Attestationheader, verifies it (audience-pinned to yourserviceDid) and slides the freshness window forward; - throws
401 attestation_requiredwhen no currently-valid attestation is on file.
server.verifyAttested(req, bodyBytes).
Strict vs extended
| Mode | Freshness window | Revocation latency | Relaxes §10.6? | Use when |
|---|---|---|---|---|
strict (default) | the attestation’s own exp (≤ 15 min, the §10.2 ceiling) | ≤ the attestation TTL | No — never serves past a token’s exp | The default. Tightest revocation. |
extended | sessionTtlSeconds, refreshed on each presentation | up to sessionTtlSeconds | Yes, for these sessions only | Strict’s re-mint cadence is too costly; you accept a longer revocation latency. |
On Cloudflare Workers
The gate is reactive — no background timer — so the only difference is whereattestedUntil lives. Use the KV-backed store from @afauthhq/worker; it sets each KV entry’s TTL to the remaining window, so lapsed sessions self-evict:
Agent side — refresh on challenge
Wrap yourAgent and TrustClient (both constructed with the same key) in an AttestedFetcher:
401 attestation_required it mints a fresh attestation (via trust.token()), re-signs with a fresh nonce, and retries once. Any other status — including a 401 with a different code — is returned unchanged.
- Reactive (default). The attestation rides only the retry, so steady-state requests carry no attestation header.
- Proactive (
proactive: true). Attach a (cached) attestation on the first attempt to skip the extra round-trip at each window boundary.
TrustHttpError — don’t retry it, re-link instead:
Revocation latency, honestly
Revoke or disable at the attestor and the agent can no longer mint. Each attested-session service then drops the account within its freshness window —strict within the attestation TTL (≤ 15 min), extended within your sessionTtlSeconds. That’s the deliberate trade-off:
- vs per-request attestation (instant revocation, but the attestor is on every request’s critical path);
- vs signup-only (no per-request cost, but never revokes — the blind spot).
Agents re-mint roughly once per service per window. The trust attestor caps mints per binding per UTC day (
TRUST_PER_BINDING_DAILY_TOKEN_LIMIT, default 10,000); raise it for very high service fan-out. A throttle returns 429 rate_limited — distinct from a revocation.Further reading
- Revocation — the global-vs-local model an attested session fits into.
- Attestation — the §10 mechanism and the
afauth-trustattestor. - Recover a compromised key — how attested sessions make an attestor-side revoke reach already-signed-up services.
- Spec §10.7 and §8.5 — normative rules and revocation coverage.