Skip to main content
The afauth-trust identifier is reserved, but the operator role is open: anyone may run an attestor under a different iss (acme-trust, enterprise-corp-trust, …) and have consuming services list it in billing.accepted_attestors. Run one for a private agent fleet (your attestor, your verification policy) or as an alternative public attestor. Consumers verify your tokens offline against your JWKS — your uptime bounds token issuance, not verification.
The wire shape is pinned by AFAP-0006 and §10.3.1 — match it exactly or no verifier will accept you. Operator policy (which verification methods you offer, abuse handling, rate limits) is entirely yours. Pick an iss other than afauth-trust.

The contract you must implement

An agent links once, then mints per-service tokens; a service fetches your JWKS and verifies offline. Concretely, you expose four endpoints (full shapes in the Trust API reference):
MethodPathPurpose
POST/v1/link/startAgent submits its DID + public key; you return a deep link for a human to confirm, plus a poll URL.
POST/v1/link/pollAgent (signing req_id) retrieves its binding once a human confirms.
POST/v1/tokenAgent (keyless §5 request signature) mints a JWT bound to a service_did.
GET/.well-known/jwks.jsonPublic verification keys, so services verify offline. Cache 300s; publish new kids ≥900s before use.
The token you mint at /v1/token MUST have this shape, signed EdDSA with a kid present in your JWKS:
header: { alg: "EdDSA", typ: "JWT", kid: "<from your jwks.json>" }
claims: {
  iss: "acme-trust",            // YOUR issuer — not afauth-trust
  aud: "<service_did>",         // the destination service; pins the token to it
  sub: "<agent_did>",           // the linked agent's did:key
  sub_h: "<base64url pairwise human pseudonym>",
  iat: <unix>,
  exp: <iat + ≤900>,            // ≤ 900 seconds, hard cap
  verification: "email" | "oauth" | "payment"
}
Three invariants verifiers depend on — get them wrong and tokens silently fail:
  • aud = the destination service_did. A token minted for service A must not verify against service B.
  • exp − iat ≤ 900s. The revocation window. Services must not cache a single token past exp.
  • sub_h carries no PII and is pairwise: stable per (human, aud), unlinkable across services. Derive it as an HMAC of the human principal keyed per service — never the raw email/OAuth subject. Agents are did:key only (no did:web), so sub is the agent’s did:key.

Stand one up

1

Choose an issuer and a domain

Pick an iss that isn’t afauth-trust (e.g. acme-trust) and the HTTPS origin you’ll serve from (e.g. https://trust.acme.example). The iss string is what services add to accepted_attestors and what verifiers match — treat it as stable.
2

Deploy the reference attestor (or implement the contract)

The fastest path is the open-source reference implementation behind trust.afauth.org: AFAuthHQ/trust. It ships the four endpoints, keyless-mint verification, pairwise sub_h derivation, and kid rotation. Deploy it on any container host (it targets Railway/Docker).It is configured by environment — public origin, advertised JWKS URL, and the keys that protect signing material and derive pseudonyms:
VariablePurpose
PUBLIC_BASE_URLYour public origin, e.g. https://trust.acme.example. Agents sign /v1/token against this, so it must match.
JWKS_PUBLIC_URLThe canonical JWKS URL you advertise.
TRUST_KEK_BASE64AES-256-GCM key-encryption-key protecting signing-key private material.
TRUST_PSEUDONYM_KEY_BASE64HMAC key that derives the pairwise sub_h.
TRUST_ADMIN_SECRETBearer secret for the operator-only key-rotation endpoints.
The issuer is currently a constant (export const ISS in src/lib/signing.ts) pinned to afauth-trust — fork and set it to your identifier. Everything else above is environment configuration. (If you implement the wire shape from scratch instead, the Trust API reference is the normative request/response contract.)
3

Get services to accept you

Verification is offline and per-service — there is no central registry to register with. Ask each consuming service to add your iss to its discovery document and point a verifier at your JWKS:
import { JwksAttestor, MultiAttestor, trustAttestor, Server } from "@afauthhq/server";

const server = new Server({
  // ...
  attestor: new MultiAttestor([
    trustAttestor(),                       // keep afauth-trust if they want both
    new JwksAttestor({
      iss: "acme-trust",
      jwksUrl: "https://trust.acme.example/.well-known/jwks.json",
      algorithms: ["EdDSA"],
    }),
  ]),
  discovery: {
    // ...
    billing: { unclaimed_mode: "attested_only", accepted_attestors: ["afauth-trust", "acme-trust"] },
  },
});
(With defineService instead of raw new Server, accepted_attestors is derived from the attestor’s issuers automatically — see Accept an attestor.)The service-side walkthrough — discovery declaration, policy, failure modes — is Accept an attestor. Because consumers pin the JWKS URLs they trust, your attestor is honored only by services that explicitly list your iss.
4

Point agents at you

Agents link to your base URL and mint exactly as they would against the default attestor:
afauth trust link --base https://trust.acme.example
afauth signup https://api.example.com   # picks the acme-trust binding the service accepts
The agent-side details — multiple bindings, selection, the not-accepted error — are in Use a different attestor.

Operational notes

  • Offline verification means your downtime is bounded. A /v1/token outage stops new mints; already-issued tokens keep verifying against your published JWKS until their exp.
  • Rotate keys ahead of use. Publish each new kid in your JWKS at least one 900-second window before signing with it, so consumer caches refresh without a verification gap.
  • Cap mint volume per binding. A per-binding daily token limit keeps a compromised agent key from acting as an unlimited attestation oracle (the reference attestor does this).
  • You are the global revocation lever. When a human revokes a binding, stop minting for that agent immediately; previously-issued tokens still verify until exp (≤900s), which is the window you’re trading off.

Where to next

Trust API reference

The normative endpoint, request, and JWT shapes to match.

The trust attestor

The federation model, the verification claim, and what an attestation proves.

Accept an attestor

The service side — declaring and verifying your iss.

Use a different attestor

The agent side — linking to and minting from your attestor.