Skip to content
Ratify Protocol

Portable authorization across agent trust boundaries

Agents claim authority. Ratify makes it verifiable.

Ratify lets a receiving API, tool, or agent platform independently verify who authorized an agent, what it may do, and for how long, even when the agent crosses an organizational or system boundary. The principal signs a portable proof, it travels with the agent, and the receiver verifies it locally.

DelegatePresentVerify
Hybrid Ed25519 + ML-DSA-65 signaturesVerification runs locally at the receiverOpen protocol · Go, TypeScript, Python, Rust, C/C++ SDKs

one verification, rendered

Delegation chain, signed by each issuer

operations → assistant agent → scheduling agent

meeting:* + identity:delegate, narrowed to meeting:attend

  • signatures: Ed25519 + ML-DSA-65
  • chain continuity: 2 hops
  • sub-delegation gate
  • effective scope: meeting:attend
  • challenge freshness
  • revocation, per local policy
valid:authorized_agent0.4 ms compiled · no vendor call
rejected:bad_signaturethe same proof, one byte altered

One proof, three verbs

Signed by a principal. Bound to an agent key. Independently verifiable by the receiver.

01

Delegate

A principal grants an agent narrow authority: an allowed scope, constraints, and an expiry.

Delegation, signed by the principal

meeting:* + identity:delegate · expires 14:30

sig: Ed25519 ✓ · ML-DSA-65 ✓ (both signatures must verify)

issued by Operations · subject: assistant-agent

02

Present

The proof travels with the agent. At the boundary, the receiver issues a fresh challenge and the agent countersigns it with the delegated key, so a copied proof cannot act as a bearer credential.

agent + proofreceiver

trust boundary

challenge nonce, fresh, single use

countersigned with the delegated key ✓

03

Verify

The receiver checks signatures, delegation continuity, scope, constraints, freshness, and its revocation policy before applying local policy. Verification runs locally when trust anchors and sufficiently fresh revocation state are already in hand.

  • signatures: Ed25519 + ML-DSA-65
  • chain continuity + delegation gate
  • scope intersection
  • constraints vs live context
  • freshness of the challenge
  • revocation, per local policy
valid:authorized_agentrejected:constraint_deniedrejected:bad_signature

Every code above comes from the verifier: a specific status when available, otherwise the machine-readable reason returned with invalid. Nothing on this site invents a code.

One proof model, many boundaries

APIMCP serverA2A agentvoice agentmeeting agentrobot or drone

The same delegation, presentation, and verifier algorithm runs wherever an agent’s request crosses a trust boundary. Two of those boundaries are playable below.

A live protocol challenge

Break the proof

Every mission below runs a real signed Ratify proof through the real TypeScript verifier, in your browser, against canonical fixtures from the protocol repository. Try to get authority the principal never granted. Each attempt returns the exact protocol result, the receiver’s own policy decision, and the measured verification time.

Now do it in your stack

The verifier you just played is the one you install

Every verdict in the lab came from the published TypeScript SDK. The receiving side is a dozen lines: decode the proof, verify the delegation chain against your own clock and revocation list, and route on the exact status.

The verifier returns the effective scope the chain actually grants, after intersecting every hop. Expected result for a valid presentation: identity_status: "authorized_agent", with the effective scope the chain actually grants. Anything else arrives as a deterministic reason you can log, alert on, and audit.

Reference SDKs in Go, TypeScript, Python, Rust, and C/C++. Same wire format, same statuses, byte-identical across all five.

npm install @identities-ai/ratify-protocol
import { verifyBundle, decodeProofBundle } from "@identities-ai/ratify-protocol";

// The receiver's side, before executing any agent-requested action:
const bundle = decodeProofBundle(request.body.proof);

const result = await verifyBundle(bundle, {
  required_scope: "meeting:attend",
  now: Math.floor(Date.now() / 1000),
  is_revoked: (certId) => revocationList.has(certId),
});

if (result.identity_status !== "authorized_agent") {
  return reject(result.identity_status, result.error_reason);
}
executeAction(); // evidence verified, locally
Copy the receiver example:

What your stack already proves, and the evidence it is missing

An external agent requests a consequential action across your trust boundary. Follow that one request through the layers you already run. Each does its job. Across an external trust boundary, the receiver can still lack portable evidence of the agent’s delegated authority.

  1. Your IdP and IAM

    Establishes who the principal is and governs your organization’s identities.

  2. OAuth and XAA

    Get the agent’s application in the door, with tokens your identity provider controls.

  3. Your policy engine

    Decides your local rules, given inputs it trusts.

  4. Ratify proof, verified here

    Who delegated what, to which agent key, under which limits. Checked locally, before anything executes.

  5. The action runs

    Or it does not, with the exact reason.

Ratify gives the receiving system cryptographic evidence that this agent was delegated this exact authority, not just a token saying the application was allowed in.

Keep your IAM, OAuth, MCP, A2A, and policy engine. Ratify adds portable proof of delegated authority at the point of action, and your system verifies it before executing.

Verify what arrives. Constrain what you send.

For receivers

Execute or reject an external agent’s request on evidence you can verify yourself.

Your API, MCP server, or platform executes actions requested by agents you do not operate. Ratify gives you a deterministic check of the agent’s delegated authority, evaluated locally against your own trust anchors and revocation policy, before the action runs.

For operators

Prove and limit what your agents may do outside your boundary.

Scope, constraints, and expiry are signed into the delegation, and revocation is a list you publish. The natural starting point is one organization on both sides: constrain your own agents, verify them at your own boundaries, then extend the same proofs to partners.

Technical architecture

A portable proof, not another control plane in the path

Ratify’s cryptographic core is deterministic across five reference SDKs. The verifier runs where the action is received: an API gateway, MCP server, agent platform, edge service, or physical system.

The proof bundle

A signed delegation chain binds the principal, agent key, scope, constraints, and expiry. Sub-delegation requires an explicit identity:delegate grant.

The verification path

The receiver checks hybrid signatures, chain continuity, proof of possession, scope, constraints, freshness, and revocation before its own policy runs.

Sessions and streams

Verify the full bundle once at session start. Repeated turns use a session token and fresh challenge signature rather than resending the complete chain.

Your deployment controls

You choose trust anchors, revocation freshness, policy hooks, and audit retention. Ratify defines the interoperable proof; those operational decisions stay with you.

Protocol evidence, with sources

63

canonical fixtures

byte-identical across SDKs

5

reference SDKs

Go · TS · Python · Rust · C/C++

0.39

ms verify, compiled

depth 1 · Apple M2 Pro

alpha.15

current release

open spec, CC-BY-4.0

Current release
1.0.0-alpha.15 (alpha: fixture bytes may change between pre-releases)
Reference SDKs
Go, TypeScript, Python, Rust, and C/C++
Conformance
63 canonical fixtures; every SDK must reproduce each byte for byte
Verify latency
Compiled verifiers 0.39 to 0.83 ms at depths 1 to 3; TypeScript 7.4 to 14.9 ms; streamed session turns 0.21 ms (Go). Measured 2026-07-25, Apple M2 Pro.
Cryptography
Hybrid Ed25519 + ML-DSA-65 (FIPS 204) on every signed object; both must verify
License
Open specification (CC-BY-4.0); Apache-2.0 reference SDKs

Sources: specification, benchmark methodology, repository.

Bring us your real authorization boundary

We are working with agent platforms and receiving systems to make delegated authority portable across trust boundaries. A design partnership starts at one real authorization point, then tests the trust, revocation, policy, and audit model under your operating conditions.

  • Receive agents: verify authority before your API, tool, or platform executes.
  • Operate agents: constrain what they may do outside your boundary.
  • Operate both sides: establish the deployment pattern internally, then extend it to partners.

Tell us where authority crosses a boundary

We ask for deployment context so the first conversation can be technical and specific.

Chuks reviews every submission.

What verification proves, and what it does not

A valid result establishes

  • The presented delegation chain is cryptographically valid.
  • Each delegation is continuous with the next subject and key.
  • Requested scope and encoded constraints are satisfied by verifier-supplied context.
  • The proof is within its validity period and satisfies the verifier's freshness and revocation policy.
  • The presenting agent proves possession using the request challenge.

It does not establish

  • That the root key belongs to a particular real-world organization or person. Trust anchors are the verifier's explicit choice.
  • That verifier-supplied facts about the physical world are true.
  • That a validly authorized action is wise, harmless, compliant, or locally permitted.
  • That offline verification means revocation data never needs refreshing.
  • That an agent is non-malicious.

High-risk deployments should fail closed when sufficiently fresh revocation state is unavailable. The full threat model and trust bootstrap modes are in the specification’s security considerations.

How does a verifier trust the principal’s key in the first place?

Not from the protocol, and the specification says so plainly. A signature proves possession of a key, never that the key belongs to the name attached to it. The verifier chooses its trust anchors through an explicit deployment decision: pin partner keys during onboarding, resolve them through a fail-closed registry read, or accept a self-published key once and require signed rotation statements from then on. A key that arrives with the proof itself is never a trust root. If a vendor tells you their protocol solved this, ask them where the first key came from.

If verification is local, how can revocation ever be fresh?

Verification runs locally; revocation state has an age, and the verifier owns that dial. Issuers publish signed revocation lists and push updates; verifiers bound how stale a view they will act on, sized to the risk of the action. When revocation state is required and unavailable, the verifier fails closed rather than assuming nothing was revoked. For irreversible actions, a forced live check is the recommended posture, and short certificate lifetimes bound the exposure either way. This is the same tradeoff every token system carries; Ratify makes it explicit policy instead of a surprise.

Start where you receive

Verify what arrives. Constrain what you send.

One authorization point is enough to start: decode, verify, route on the status. The proof travels; no vendor has to.