Skip to content

Go SDK

The Go SDK is the reference implementation. Every other SDK is byte-for-byte compatible with it.

Terminal window
go get github.com/identities-ai/ratify-protocol@v1.0.0-alpha.6

The module is github.com/identities-ai/ratify-protocol. Go 1.25+ recommended.

The example below is the entire protocol in 30 lines. Alice creates her root identity, signs a delegation to her agent, the agent builds a proof bundle, and a verifier runs the verifier algorithm. No HTTP, no servers — just function calls.

package main
import (
"fmt"
"time"
"github.com/identities-ai/ratify-protocol"
)
func main() {
// 1. Alice generates her hybrid root identity.
alice, alicePriv, _ := ratify.GenerateHumanRootKeypair()
// 2. Her AI agent generates its own hybrid keypair.
agent, agentPriv, _ := ratify.GenerateAgentKeypair("Alice's Scheduler", "custom")
// 3. Alice signs a delegation cert for the agent.
cert := &ratify.DelegationCert{
Version: 1,
IssuerID: alice.ID,
IssuerPubKey: alice.PublicKey,
SubjectID: agent.ID,
SubjectPubKey: agent.PublicKey,
Scope: []string{"meeting:attend", "meeting:speak"},
IssuedAt: time.Now().Unix(),
ExpiresAt: time.Now().Add(7 * 24 * time.Hour).Unix(),
}
_ = ratify.IssueDelegation(cert, alicePriv)
// 4. Verifier issues a challenge. Agent signs it.
challenge := ratify.GenerateChallenge()
challengeAt := time.Now().Unix()
challengeSig, _ := ratify.SignChallenge(challenge, challengeAt, agentPriv)
// 5. Agent assembles a proof bundle.
bundle := &ratify.ProofBundle{
AgentID: agent.ID,
AgentPubKey: agent.PublicKey,
Delegations: []*ratify.DelegationCert{cert},
Challenge: challenge,
ChallengeAt: challengeAt,
ChallengeSig: challengeSig,
}
// 6. Verifier runs the verifier.
result := ratify.VerifyBundle(bundle, ratify.VerifyOptions{
RequiredScope: "meeting:attend",
})
if result.Valid {
fmt.Printf("✓ Authorized: %s, granted: %v\n", result.AgentID, result.GrantedScope)
} else {
fmt.Printf("✗ Rejected: %s%s\n", result.IdentityStatus, result.ErrorReason)
}
}

Run it: go run main.go. Output: ✓ Authorized: <agent-id>, granted: [meeting:attend meeting:speak].

┌─────────────┐ ┌─────────────┐
│ Alice │ 1. GenerateHumanRootKeypair │ Verifier │
│ │ 2. IssueDelegation(cert) │ │
│ private │ │ │
│ key on │ │ │
│ her dev │ │ │
└──────┬──────┘ └─────▲───────┘
│ │
│ cert (signed) │ 6. VerifyBundle
▼ │ → Valid + Scope
┌─────────────┐ ┌─────┴───────┐
│ AI Agent │ 3. GenerateAgentKeypair │ │
│ │ 4. SignChallenge(nonce) │ │
│ cert + │ 5. ProofBundle{...} │ │
│ own keys │ ────────────────────────────────▶│ │
└─────────────┘ └─────────────┘
Alice's private key never leaves her device.
Agent never sees Alice's private key.
Verifier never sees any private key — only public keys + signatures.

If you’re building a Ratify verifier (the receiving party that checks proofs), VerifyBundle is the entire verifier algorithm in one call:

result := ratify.VerifyBundle(bundle, ratify.VerifyOptions{
RequiredScope: "meeting:attend", // What action is being attempted?
RequiredCustomScope: "", // Optional custom: scope
NowOverride: nil, // Use real time (test only)
RevocationList: revList, // Optional signed revocation list
})
// Branch on result.IdentityStatus:
switch result.IdentityStatus {
case ratify.StatusValid:
// ✓ accept the request
case ratify.StatusBadSignature:
// ✗ cert was tampered after signing
case ratify.StatusExpired:
// ✗ cert is past its expires_at
case ratify.StatusScopeDenied:
// ✗ requested scope not in granted chain
case ratify.StatusRevoked:
// ✗ matched a revocation list entry
case ratify.StatusReplay:
// ✗ challenge is older than the freshness window
}

The verifier is fail-closed by default. Any error path returns “not valid” — you cannot accidentally accept a malformed bundle.

If the delegation has constraints, pass the runtime context:

result := ratify.VerifyBundle(bundle, ratify.VerifyOptions{
RequiredScope: "physical:move",
Context: &ratify.VerifyContext{
Location: &ratify.GeoPoint{Lat: 37.77, Lon: -122.41}, // Verifier's location
Now: time.Now(),
Version: "agent-fw-1.2.3",
},
})

The verifier will reject the bundle if the agent is outside the allowed geo radius, outside the allowed time window, or running a version excluded by the constraint. See Constraints for the full constraint vocabulary.

Agent-to-agent delegation is the same primitive. Agent-A delegates to Agent-B; the bundle just carries two certs:

// Agent-A signs a sub-delegation to Agent-B
subCert := &ratify.DelegationCert{
Version: 1,
IssuerID: agentA.ID,
IssuerPubKey: agentA.PublicKey,
SubjectID: agentB.ID,
SubjectPubKey: agentB.PublicKey,
Scope: []string{"meeting:attend"}, // Subset of what A was given
IssuedAt: now,
ExpiresAt: now + 24*3600,
}
ratify.IssueDelegation(subCert, agentAPriv)
// Agent-B's bundle now has two delegations (the chain)
bundle := &ratify.ProofBundle{
AgentID: agentB.ID,
AgentPubKey: agentB.PublicKey,
Delegations: []*ratify.DelegationCert{cert, subCert}, // chain: Alice → A → B
Challenge: challenge,
ChallengeAt: challengeAt,
ChallengeSig: agentBSignature,
}
// Verifier checks the WHOLE chain. Effective scope is the intersection.
result := ratify.VerifyBundle(bundle, ratify.VerifyOptions{RequiredScope: "meeting:attend"})

Effective scope is the intersection across all links. Agent-B can never get more than Agent-A was given, which can never be more than Alice gave Agent-A.

Terminal window
cd ratify-protocol
go test ./...

If you see ok github.com/identities-ai/ratify-protocol, all 59 fixtures passed and your implementation is byte-for-byte interoperable with every other Ratify SDK.

The repo also ships a ratify CLI for human use — create identities, sign delegations, verify bundles, list the canonical scopes:

Terminal window
go build -o /tmp/ratify ./cmd/ratify
/tmp/ratify --help

Common workflows:

Terminal window
# Create a HumanRoot identity (writes to ~/.ratify/)
ratify init
# Generate an agent keypair
ratify agent-init
# Sign a delegation
ratify delegate \
--agent-pubkey-file agent-pubkey.json \
--scope "meeting:attend,meeting:speak" \
--days 7 \
--out delegation.json
# Verify a bundle
ratify verify bundle.json
# Print the canonical 52-scope vocabulary
ratify scopes