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: 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:keysignature 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-sideaccount_id— §10.4.4, “one account, many devices” — so a post-claim re-key keeps the same account; thedid:keyitself 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:| Storage | When it’s enough | When it isn’t |
|---|---|---|
File on disk (mode 0600) | Local development, scripts | Anywhere an attacker might read the FS |
| OS keystore (Keychain, Credential Manager, Secret Service) | Single-user agents | Multi-user or server deployments |
| TPM / Secure Enclave / HSM | Production agents on managed hosts | — |
| Cloud KMS with signing-only access | Server-side agents at scale | — |
~/.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 isUNCLAIMED/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 samedid: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
- Signing requests — what the agent does with the key.
- Spec §3 — normative identity rules.
- Spec §12.1 — key compromise threat model.