> ## Documentation Index
> Fetch the complete documentation index at: https://docs.afauth.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Revoke an account

> Owner-authenticated revocation: cut off a compromised or retired agent key at your service.

Revoking an account's key stops it cold at your service — the next request signed by that key fails with `401 revoked_key`. Revocation is an **owner-binding operation**: it's gated on a fresh owner-authenticated session, never the agent's signature (the whole point is that the key may be stolen). An agent cannot revoke its own claimed account — that's the [two-step-verify invariant](/concepts/ceremony).

## Turnkey: `handleKeyRevocation`

If you advertise the `key_revocation` endpoint, extract the owner session with your own auth layer and hand the request to the SDK:

```ts theme={null}
// POST /afauth/v1/accounts/me/keys/revoke — body { account_id } or { agent_did }
export async function handleOwnerRevoke(req: Request, session: OwnerSession) {
  return server.handleKeyRevocation(req, session);
}
```

Name the account directly by `account_id`, or by any one of its agent credentials via `agent_did` (revoke the account that device belongs to). It enforces the §7.5 freshness floor, checks the session owns the account, then revokes — blocking **every** credential on the account (§10.4.4: one account, many devices). Response: `200 { account_id, revoked_at }`. Re-revoking is idempotent.

## Bare primitive: `Server.revoke(accountId)`

For internal or abuse-handling tooling, `Server.revoke(accountId)` marks the whole account revoked and adds every one of its agent credentials to the revocation list. It's **un-gated**, so you must gate it on a fresh owner session yourself. If you only hold a credential DID, resolve its account first:

```ts theme={null}
assertFreshOwnerSession(session, { maxAgeSeconds: 120 });
const account = await accounts.getByAgentDid(did); // resolve the credential → its account
await server.revoke(account.accountId);
```

See [`examples/recipes/revoke.ts`](https://github.com/AFAuthHQ/typescript-sdk/blob/main/examples/recipes/revoke.ts) for both paths.

## After revoke: resume by re-keying

Revoke pauses the agent. To bring it back, the owner **re-keys** — installs a fresh key on the same account from an owner session (§8.2). Walk the full incident flow in [Recover a compromised key](/guides/recover-a-compromised-key).

## Coverage & limits

This is the **local** lever; the [revocation model](/concepts/revocation) sets it beside the global one (an attestor-side binding revoke).

* **Per-service.** Revocation is local to your service; there's no cross-service revocation transport (§8.3). An owner recovering from compromise acts at each service *and* at the trust attestor.
* **In-flight attestations.** If you gate on [trust attestations](/concepts/trust-attestor), revoking the binding at the attestor stops *new* tokens — already-issued ones stay valid until they expire (≤ 15 min). Revoke at your service too for an immediate cut-off. Recovering a stolen key end to end? Follow the ordered runbook in [Recover a compromised key](/guides/recover-a-compromised-key).

Spec: [§8.4](https://github.com/AFAuthHQ/spec/blob/main/spec/core.md#84-owner-initiated-revocation), [§8.5](https://github.com/AFAuthHQ/spec/blob/main/spec/core.md#85-revocation-coverage-and-its-limits).
