Skip to content

Authorisation Warrant, format v1 (final)

Status: final, version 1, published with Phase 10 of the Authorisation Layer programme. Test vectors and the conformance suite are in the open formats bundle (spec/xybern-formats-v1/vectors/warrant.json). Feedback: security@xybern.com.

An Authorisation Warrant is a short-lived signed capability that an AI agent carries. It states, in a form any party can check offline with the issuer's published public key, what the agent is authorised to do, on whose authority, within which bounds, and until when. It is issued from the objects in force at the moment of issue (the signed Charter version, the agent's access profile, its intent contract, its runtime session budget, its credential) and it can be attenuated when authority is delegated: a child warrant can only narrow its parent, never widen it.

Token

xwt1.<base64url( canonical_json({"body": <body>, "signature": <signature>}) )>

base64url without padding. The prefix xwt1. identifies the format. The token is safe to carry in an HTTP header (Xybern-Warrant), a JSON field (warrant), or an MCP request header.

Body

Canonical JSON: keys sorted, no whitespace, UTF-8, no escaping of non-ASCII.

Field Type Meaning
format string "xybern-warrant-v1"
warrant_id string wrt_ followed by 12 hex characters, unique per issuer
issuer object {"workspace_id": ..., "key_id": ...}, the issuing workspace and the signing key used
holder object {"agent_id": ..., "fingerprint": ... or null, "did": ... or null}, the agent the warrant is bound to. fingerprint is the SHA-256 fingerprint of the agent's Ed25519 credential when it has one
charter_hash string or null The Charter version in force at issue (public sha256 over the canonical mandate list)
policy_set_hash string or null The compiled rule set hash in force at issue
authority object See below
session_id string or null The runtime session the warrant is bound to
grant_id string or null The delegation grant it was issued through
not_before string ISO 8601 UTC, seconds precision, Z suffix
expires_at string ISO 8601 UTC
depth integer 0 for a root warrant, parent.depth + 1 for a child
chain array of strings The body hash (sha256 hex over the canonical body) of every ancestor, root first
caveats array of objects Informational narrowing statements ({"type": "access_profile", ...}, {"type": "delegation", ...}, {"type": "standing_authority", ...}). Not evaluated by checkers
issued_at string ISO 8601 UTC
contract_id, root_agent_id string or null The mission (intent contract) the warrant serves and the root of its delegation chain
constraints object, optional (XAO 0.2) {"decay": {"full_seconds", "held_seconds"} or {"full_uses", "held_uses"}, "lease": {"heartbeat_seconds", "requires_session", "requires_parent"}}. Decay by age is checked offline (past held_seconds the warrant is refused; past full_seconds the issuer holds actions for approval); decay by uses and every lease prerequisite are issuer state. A child inherits and may only tighten them

authority

Field Type Meaning
action_families array of strings Action types the warrant covers. * covers everything; a trailing * is a glob (send_*)
scopes array of strings Credential scopes in force, informational for checkers
argument_bounds object {<family>: {<field>: <rule>}}. A rule is any of {"max": n}, {"min": n}, {"in": [...]}, {"not_in": [...]}, optionally "required": false (default true: a bounded field that is absent from the action fails the check)
budgets object {"max_actions": n}, enforced by the issuer, which counts uses
resources array of strings, optional (XAO 0.1) Resource class patterns the warrant covers (tool:payments, mcp:github/*, data:PUBLIC, class#instance_hash); absent or * covers every resource

Signature

{"algorithm": "ecdsa-p256-sha256", "key_id": <issuer signing key id>, "value": <base64(DER ECDSA signature)>}

The message signed is the canonical JSON bytes of body. The key is one of the issuer's published signing keys: GET /api/sentinel/vault/keys (the Provenance Vault key page) or GET /v1/enforce/warrants/keys. Keys rotate; retired keys stay published so older warrants still verify within their window.

Checks

A checker with the published keys and no network access verifies, in order:

  1. the token decodes and format is xybern-warrant-v1
  2. signature.key_id is a published key and the ECDSA signature over the canonical body verifies
  3. not_before <= now < expires_at
  4. holder.agent_id is the acting agent; when the request carries a verified identity assertion and holder.fingerprint is set, the fingerprints match
  5. authority.action_families covers the action type
  6. authority.argument_bounds for the covering family are satisfied by the action's parameters
  7. when session_id is set, the action runs in that session

Issuer state, checked online or through the issuer's signed revocation list:

  1. the warrant is not revoked
  2. budgets.max_actions is not exhausted

Any failure refuses the action. An unparseable, unsigned or unknown-key token is not a warrant.

Attenuation

A child warrant issued from a parent must satisfy, at issue time and again on every check of the chain:

  • every child action family is covered by a parent family (* in the parent covers all)
  • child scopes are a subset of the parent's, when the parent lists any
  • for every family and field the parent bounds, the child bounds it at least as tightly (max not larger, min not smaller, in a subset, not_in a superset)
  • budgets.max_actions not larger than the parent's, when the parent sets one
  • expires_at not later than the parent's
  • depth equals the parent's plus one, and chain equals the parent's chain plus the parent's body hash

The issuer refuses to sign a child that would widen. Revoking a warrant revokes every descendant.

Revocation list

GET /v1/enforce/warrants/revocations?since=<seq>
{"list": {"format": "xybern-warrant-revocations-v1", "workspace_id", "as_of", "since_seq", "latest_seq",
          "complete", "revoked": [{"warrant_id", "seq", "revoked_at", "body_hash"}]},
 "signature": {"algorithm": "ecdsa-p256-sha256", "key_id", "value"}}

Signed over the canonical list. seq is a strictly increasing per-workspace counter, so a relay keeps latest_seq and pulls incrementally. A relay that cannot refresh the list within its grace window refuses warrant-bearing actions (fail closed) unless configured to fail open.

Reference implementations

  • Issuer and choke-point check: package/xybern_api/warrants.py
  • Python offline checker and self-refreshing holder: xybern.warrants in the xybern package (pip install xybern[crypto])
  • Command line: tools/xybern-verify/verify.py --warrant <token> --keys keys.json [--action <type>] [--metadata '{...}']
  • Self-hosted relay: xybern_relay/warrant_check.py