Skip to main content
An AFAuth agent account is named by a did:key Decentralized Identifier (W3C DID) — the identifier is the agent’s public key. This is the only agent account method in v0.1.
did:web is not an agent account method. Agents typically run on user machines behind home routers, with no stable web origin at which to host a DID document — so a DNS-anchored identity isn’t usable for the common agent. did:web still appears elsewhere in AFAuth — for a service’s own service_did (services have hosts) and for owner recipients — just never as the agent’s key.

did:key

A did:key identifier encodes the public key directly into the identifier:
did:key:z6MkiYbwC5honA2sxE7XLAyJMDFibLvVg8FgodBX4A4CaUgr
The multibase string after did:key: is the multicodec prefix for Ed25519 (0xed01) followed by the 32-byte raw public key, base58btc-encoded. A service verifying a did:key signature decodes the string locally and uses the recovered public key directly — no registry lookup, no DNS. The identifier is the key. Tradeoffs:
  • Verifiable offline. Anyone can verify a did:key signature with just the DID string and the signature itself.
  • Cheap to generate. Agent.generate() in the TypeScript SDK takes microseconds.
  • The DID changes when the key changes. Rotating the key changes the agent’s did:key, so external references to the old DID stop resolving. (A service may group a human’s credentials under a stable, service-side account_id — §10.4.4, “one account, many devices” — so a post-claim re-key keeps the same account; the did:key itself is still not a stable identifier.) Recovery from a lost or compromised key is therefore owner-driven (revoke + re-key). See Recover a compromised key.
Why not a stable, DNS-anchored identifier (did:web) for agents? Because agents run on laptops and in containers behind home routers — they have no stable web origin to host a DID document. The did:key-changes-on-rotation tradeoff is accepted in exchange for zero-registration, offline-verifiable identity, and the recovery story is owner revoke + re-key rather than a stable DID. (did:web is still right for a service’s own service_did, which does have a host.)

Key handling

The agent’s private key is the sole credential for pre-claim operations: while an account is unclaimed, there’s no recovery path other than re-creating it. Once a human has claimed the account, recovery shifts to the owner — they can revoke the key and re-key the account from an owner-authenticated session, without the agent’s (possibly stolen) key. See Recover a compromised key. Storage recommendations, in increasing order of robustness:
StorageWhen it’s enoughWhen it isn’t
File on disk (mode 0600)Local development, scriptsAnywhere an attacker might read the FS
OS keystore (Keychain, Credential Manager, Secret Service)Single-user agentsMulti-user or server deployments
TPM / Secure Enclave / HSMProduction agents on managed hosts
Cloud KMS with signing-only accessServer-side agents at scale
The reference CLI stores the active key at ~/.afauth/key.json with mode 0600. The TypeScript SDK lets you supply your own seed via Agent.fromPrivateKey(seed) so you can plug into any of the above.

Rotation

Ed25519 verification keys have no usage-based wear, so there’s no need for routine, scheduled rotation. You change a key for exactly two reasons — to migrate identifiers, or to recover from compromise — and how you do it depends on whether the account is claimed. Pre-claim (agent-driven). While the account is UNCLAIMED/INVITED, the agent rotates by signing a rotation request with the old key; the service decommissions the old DID (adds it to the revocation list) and accepts the new one. The agent’s did:key changes — the DID is the key — so external references to the old DID stop resolving. See Rotate keys. Post-claim (owner-driven). Once claimed, the agent’s signature alone can no longer change the key — that would break the two-step-verify invariant. The owner revokes and re-keys from a fresh owner-authenticated session. This is the compromise-recovery path: see Recover a compromised key.

Per-service keys

By default, an agent that signs up to multiple services with the same did:key is correlatable across those services. Agents that require unlinkability MUST derive per-service keys — the spec (§3.3) suggests HKDF-based derivation from a master seed. The v0.1 SDK does not ship a per-service derivation helper; bring your own or generate fresh agents per service.

Further reading