Docs Start here
Concepts
SPIFFE, SPIRE and SVIDs; trust domains and bindings; the evidence model and the three checks; delegations; and the signed assertion.
The big picture
SPIFFE, SPIRE and SVIDs
SPIFFE is the standard for workload identity. A workload's identity is a SPIFFE ID such as spiffe://agents.payments.example.com/agent/checkout: a trust domain (agents.payments.example.com) and a path (/agent/checkout). The workload proves that identity with an SVID (SPIFFE Verifiable Identity Document), which is an X.509 certificate or a JWT.
SPIRE is the reference implementation. A SPIRE server holds the signing authorities of one trust domain, attests workloads and issues them short-lived SVIDs. Anyone who holds the trust domain's bundle (its public authorities) can validate those SVIDs.
What SPIFFE does not say is which organization operates a trust domain. A DNS-shaped name proves nothing about DNS ownership, and receiving a bundle from a peer proves nothing about who the peer is. Agentic Root Trust fills that gap: it records which verified organization authorized a trust domain, and publishes the bundle that organization approved.
The directory supports the spiffe-x509 profile: X.509-SVID verification over mTLS. JWT-SVID and WIMSE (Workload Identity Token and Workload Identity Certificate) adapters are later, separately specified profiles.
Trust domains
A trust domain in the directory is always exact: lowercase [a-z0-9._-], at most 255 characters, no empty labels, not an IP address, and never written with a spiffe:// prefix. There is no wildcard or parent-domain matching, so resolving agents.example.com says nothing about eu.agents.example.com.
A trust domain is tied to a verified domain claim in one of two ways:
| Mapping | Rule |
|---|---|
dns (default) |
The trust domain is the claim's domain or a DNS name under it, such as agents.payments.example.com under payments.example.com. |
explicit |
A single-label trust domain (no dots), mapped to the claim by a reviewer. |
Public suffixes and special-use names (.example, .test and similar) are refused. Only one organization holds a live binding for an exact trust domain at a time.
Bindings
A binding is the directory's record that an organization authorized an issuer. It ties together:
- the organization and the verified claim that backs it;
- the exact trust domain and the profile (
spiffe-x509); - the workload scope: the SPIFFE ID path prefixes the issuer may speak for;
- a numbered, immutable version carrying the federation bundle endpoint and the exact bundle bytes and their SHA-256 digest.
A binding moves through draft → pending_review → active, and from there to suspended, expired or withdrawn. withdrawn and expired are terminal. Key material is never overwritten: a changed bundle is always a new version, and superseded versions stay fetchable at their own URL. An active binding is endorsed until its expires_at, at most one year, capped by everything it depends on (the representative authority, the claim, the CA certificates' validity, the issuer-control evidence and any delegation).
Workload scope
The scope is a list of 1 to 64 path prefixes. Each starts with /, has at least one segment, and each segment is [A-Za-z0-9._-]+ with no . or .. segments and no percent-encoding. Matching is by whole segment: /payments matches /payments/api but never /payments-evil.
The three checks
A claim on a domain is verified only when all three checks pass. None can be skipped, and each is recorded and shown separately.
- Domain control. An authenticated account publishes a single-use token in a DNS TXT record at
_workload-directory.<domain>. Both Cloudflare and Google public DNS must see it. This proves control of the name now; it is re-checked every 90 days. - Organization identity. A reviewer checks the organization's evidence against its legal name, jurisdiction and registration. A DV certificate alone cannot complete this check.
- Representative authority. A reviewer confirms, through an independently sourced contact at the organization, that the claimant may act for it. Company email, uploaded documents and DNS access are never enough on their own. The approval names the permitted actions (
authorize_issuer,delegate,manage_domain) and expires within a year.
A claim moves pending_domain → pending_identity → pending_authority → verified. It can also be needs_information, rejected, disputed, expired, suspended or withdrawn. Conflicting claims go to review; they are never settled by whoever claimed first.
The evidence model
The directory borrows the TLS validation levels so that relying parties compare like with like, and keeps every other kind of evidence separate.
| Evidence | What it supports |
|---|---|
| DV | Domain control was validated for certificate issuance |
| OV | DV plus vetted organization information |
| EV | OV plus prescribed organization-existence and applicant-authority checks |
| Directory DNS challenge | The account can satisfy the current domain-control challenge |
| Representative review | The claimant may represent the named organization for the approved actions |
| Issuer authorization | The verified representative explicitly approved this issuer, bundle and scope |
Certificates the directory observes are classified only after path, hostname and validity checks against a pinned, versioned trust store; organization fields alone never make a certificate OV or EV, and unknown policies stay unknown. A TLS observation is a historical record of what a host served, never a verdict. A CDN-served DV certificate does not downgrade separately reviewed identity.
There is no numerical trust score. DV, OV and EV describe evidence, not legitimacy or agent safety: a fully verified organization can still run a careless or compromised agent.
Delegations
A parent organization can delegate a strict subdomain of its verified claim to another organization, with a limited set of actions (authorize_issuer, manage_domain), a workload scope inside its own, and an expiry. Control of a child grants nothing over the parent or its siblings, re-delegation is refused, and cycles are rejected. A delegation is active only after the recipient's owner accepts it and a reviewer approves it. See Withdrawal and delegations.
The assertion
GET /v1/resolve?trust_domain= returns a compact JWS. It is a directory assertion, not an SVID or a WIMSE credential. The protected header is exactly:
{"alg":"ES256","typ":"art-resolution+jwt;v=1","kid":"<RFC 7638 thumbprint of the signing key>"}
The payload of the example in the API description decodes to:
{
"iss": "https://svid.io",
"aud": "workload-directory-resolver-v1",
"iat": 1791201600,
"nbf": 1791201600,
"exp": 1791201900,
"schema_version": 1,
"binding_id": "bnd_9r2t5w8z1b4d7f0h3k6n9q2s5v",
"binding_version": 1,
"status": "active",
"organization_id": "org_7k3m9q2x8d5f1h4j6n0p2r4t8v",
"organization_name": "Example Payments, Inc.",
"verified_domain": "payments.example.com",
"trust_domain": "agents.payments.example.com",
"profile": "spiffe-x509",
"workload_scope": ["/agent/checkout", "/agent/refunds"],
"bundle_url": "https://svid.io/v1/issuer-bindings/bnd_9r2t5w8z1b4d7f0h3k6n9q2s5v/versions/1/bundle",
"bundle_sha256": "q7Yd3nXk0aV2pLw9sT4uHc8BzE1mR6fJ5gN0oIxK2tA",
"evidence_summary": {
"domain_control": "verified",
"organization_identity": "reviewed",
"representative_authority": "verified"
},
"policy_version": "directory-policy-v1"
}
Points that matter when you verify it:
iatis the time of the authoritative database read,nbfalways equalsiat, andexpis at mostiat + 300. The lifetime is shortened further to the earliest expiry of the binding, the claim, the 90-day domain-control window and every piece of required evidence.- The verifier allows 30 seconds of clock skew, so an assertion read just before a withdrawal can be accepted for up to 330 seconds after the withdrawal commits.
bundle_urlalways has the form<iss>/v1/issuer-bindings/<binding_id>/versions/<binding_version>/bundle, andbundle_sha256is the unpadded base64url SHA-256 of the exact bytes served there.organization_idis the stable identifier to pin. Never trustorganization_nameor any label the agent presents.- The signed bytes are canonical JSON (no whitespace, no duplicate keys) and at most 8192 bytes. Unknown fields fail verification.
The verification guide walks through every check in order.