Skip to main content
This guide turns on afauth-trust attestation support for an AFAuth service. After this, agents that link to a human at trust.afauth.org can present an offline-verifiable JWT on each request, and your service can gate features on that signal — either as a softer “free tier” filter (unclaimed_mode = "free" with attestation-aware quotas) or as a hard requirement (unclaimed_mode = "attested_only").
Accepting afauth-trust is the default posture for a spam-resistant service: defineService already wires trustAttestor() and sets unclaimed_mode = "attested_only" for you. This guide shows what that default does and how to tune it. See the trust attestor concept for what a trust attestation actually proves, and the broader attestation concept for HMAC + multi-attestor patterns.

Before you start

You need:
  1. A working AFAuth service using @afauthhq/server (or any conformant implementation). If you don’t yet, start at Accept AFAuth on your service.
  2. A service_did declared in your discovery document — trust attestations are bound to this audience.
That’s it. There’s no enrollment, no API key, no registration with trust.afauth.org. You consume a public JWKS document; no provisioning is required.

The three steps

1

Declare afauth-trust in your discovery document

Add afauth-trust to your billing.accepted_attestors list. Choose an unclaimed_mode based on how strict you want the gate to be.
If you want both afauth-trust and another attestor (e.g., an internal HMAC or stripe-projects once you’ve enrolled), list them together — the server tries each accepted issuer in turn.
2

Configure the attestor in your Server

For new integrations, the easiest path is defineService, which wires the trust attestor and the attested_only discovery declaration in one call:
If you’re already on new Server({...}) or need a custom discovery doc, use the trustAttestor() factory directly (@afauthhq/server 0.2.0+ ships it pre-pinned to the AFAP-0006 issuer, JWKS URL, and EdDSA):
For staging or local dev (e.g. running the trust attestor against a tunnelled endpoint), trustAttestor({ jwksUrl: "..." }) overrides the JWKS URL while keeping the rest of the AFAP-pinned shape. The explicit form is also available — new JwksAttestor({ iss: "afauth-trust", jwksUrl, algorithms: ["EdDSA"] }) — but rarely needed.The Verifier automatically:
  • Reads AFAuth-Attestation from the request headers.
  • Verifies the JWT’s signature against the JWKS (with caching + rotation handled by jose’s createRemoteJWKSet).
  • Validates iss == "afauth-trust", aud == your service_did, sub == signing DID, and exp in the future.
  • Rejects with 401 invalid_attestation (malformed / bad signature / wrong aud / expired) or 401 attestation_required (missing under attested_only).
Accept more than one attestor by composing them with MultiAttestor — e.g. afauth-trust plus an internal HMAC, or a self-hosted attestor under its own iss. With defineService, the attestor’s issuers are advertised in billing.accepted_attestors automatically — no need to hand-list them:
With raw new Server({...}) (no defineService) you write the full discovery document yourself, so list every iss in billing.accepted_attestors to match the attestors you wired — it isn’t derived for you there.
3

Use the verification claim in your application

When the verifier accepts an attestation, the verification claim is available to your application code. Use it however your policy needs — gate features, tier rate limits, log it.
The verification rank is your policy. The protocol takes no opinion on whether payment > oauth > email or any other ordering — each service decides what each signal unlocks. The trust attestor always emits the strongest method the linked human has on file.

Test your integration end to end

Once configured, you can validate the full path locally with the reference CLI from a fresh agent identity:
Then drive the link flow (see Link your agent to a human) to receive a trust attestation, and retry the signed request. The agent’s request will now carry an AFAuth-Attestation header and your service will accept it. This is the default agent journey end to end: an agent built from the agent quickstart links to a human and mints exactly the attestation your attested_only service requires.

Failure modes you might hit

Operational notes

  • Offline verification means uptime is bounded by your service. A brief trust.afauth.org outage does not affect verification of already-issued tokens — only the issuance of new ones (and only for the duration of the outage).
  • Don’t cache attestations beyond their exp. §10 explicitly forbids it. The 900-second cap is the revocation window.
  • You do not need to pin kid. New kids are published 900+ seconds before first use; JwksAttestor follows the JWKS, no manual key management on your side.

Where to next

Trust API reference

JWKS, link flow, token endpoint, errors.

The attestation concept

HMAC, MultiAttestor, the full §10 surface.

Spec §10

Normative attestation rules.

List on the registry

Once you accept attestations, get discovered.