fixture modeChain is mocked with three demo agents. Set THESEUS_RPC_URL to read from a Theseus node.

Docs · Reference

Revocation.

A credential is signature-valid forever. Freshness is a separate question. Revocation is how PoA tells verifiers that a still-valid signature should no longer be trusted.

Two paths into the revocation list

Operator-initiated

The controller can revoke at any time. Same shape as issuing: request a challenge, sign a revoke message, post to /poa/api/revoke. The signed message uses a different prefix from issuance, poa-revoke:<agentId>:<nonce>, so a signature collected for one operation cannot be replayed for the other.

# 1. Get a challenge
curl -X POST https://theseus.network/poa/api/challenge \
  -H 'content-type: application/json' \
  -d '{ "agentId": "5GrwvaEF...HGKutQY" }'

# 2. Sign 'poa-revoke:<agentId>:<nonce>' with the controller key
#    (same wallet flow as issuing, different prefix)

# 3. Post the revoke
curl -X POST https://theseus.network/poa/api/revoke \
  -H 'content-type: application/json' \
  -d '{
    "agentId": "5GrwvaEF...HGKutQY",
    "nonce": "...",
    "signatureHex": "..."
  }'

The credential is marked revoked with reason operator-revoked. The credential page immediately shows the void state. The verify endpoint reports freshness.status === "revoked" on the next request.

Automatic, on chain state change

PoA periodically reconciles every active credential against live chain state. A change that contradicts the signed snapshot triggers revocation with one of these reasons:

  • agent-deregistered. The agent no longer has an AgentInfo on chain.
  • balance-zero-90d. The agent is in the dormant or collectable state. State is removed at ninety days at zero seus balance; PoA marks the credential void as soon as the funding goes inactive.
  • abg-changed. The on-chain ABG hash no longer matches the snapshot. The agent's behavior surface has been updated; the old credential is no longer descriptive of what runs.
  • controller-rotated. The controller account on chain is different from the one that attested to the credential.
  • sovereignty-flipped. Only meaningful once the chain implements sovereignty. A credential issued claiming the agent was sovereign is revoked if the agent later acquires a controller.

The public list

GET /poa/api/revoked returns every revoked credential the issuer knows about. Use it for offline verification or for caching the freshness check independently of /poa/api/verify.

{
  "issuer": "theseus.network/poa",
  "generatedAt": "2026-05-03T12:00:00.000Z",
  "revoked": [
    {
      "jti": "01HQXY...",
      "agentId": "5GrwvaEF...HGKutQY",
      "reason": "abg-changed",
      "at": 1735689600000
    }
  ]
}

The list grows monotonically. Credentials do not come back from revoked. To re-credential an agent after a revoke, the operator mints a fresh credential, which gets a new jti.

What revocation does not do

  • It does not invalidate the JWS. The signature still verifies. Verifiers must check the revocation list separately. That is why /poa/api/verify reports valid and freshness as independent fields.
  • It does not touch the chain. Revocation lives in the issuer's store. The on-chain agent is unaffected.
  • It does not delete data. The original credential and its signed claims are still retrievable at /poa/api/credential/<jti> with revoked populated.

Sovereign agents and revocation

A sovereign agent has no controller, so the operator-initiated revoke path is unavailable. There is nobody authorized to sign the revoke message. This is by design: a sovereign agent's credential can only be invalidated by chain state changes that the agent itself cannot make. In the current alpha, no agents are sovereign; this constraint is documented for the future.