delegated
Fail-closed trust evaluation for agentic AI systems.
delegated verifies delegation tokens and enforces policy on every agent action — before your tools, APIs, or downstream agents run anything. Drop it in as Tower middleware, call the standalone adapters, or use the client SDK to attach trust claims to outbound requests.
What it does
- Verifies Ed25519-signed delegation tokens and agent identity documents
- Enforces configurable policy: allowed actions, max spend, delegation depth, calendar constraints, email domain allowlists, cognitive and reputation gates
- Blocks revoked tokens, emergency-denied agents, nonce replays — fail-closed on backend errors
- Audits every decision to a structured JSONL sink
- Issues delegation tokens and identity documents via fluent builders with key rotation support
Feature flags
| Flag | What it enables |
|---|---|
| (none) | Core evaluation pipeline, adapters, builders, file-backed state |
async |
AsyncTrustStateStore trait + async engine variants |
axum |
DelegatedLayer Tower middleware for axum |
client |
DelegatedClient for sending trust-validated outbound requests |
redis |
RedisTrustStateStore backed by Redis (async) |
tracing |
tracing spans on the evaluation hot path |
metrics |
metrics counters and histograms |
oidc-bridge |
IdentityVerifier trait for OIDC-based identity verification |
Quickstart — server side (axum middleware)
use Arc;
use ;
let trust_state = new;
let sink = new;
let layer = new
.with_max_body_bytes // optional, default is 1 MiB
.build;
let app = new
.route
.layer;
Every POST to /tools/call is evaluated before my_handler runs. Denied requests return 403 with {allowed, stage, reason} JSON; allowed requests pass through. Oversized request bodies return 413.
Quickstart — client side
Build a RequestEnvelope with the issuance builders and attach it to outbound requests:
use ;
use SigningKey;
let key = from_bytes;
let doc = new
.agent_id
.owner_id
.issuer
.identity_type
.subject
.key_id
// Register an additional key for rotation:
.additional_public_key
.supported_protocol
.supported_auth_method
.endpoint
.build_and_sign?;
let token = new
.issuer
.agent_id
.delegator_id
.owner_id
.audience
.allowed_action
.key_id
.expires_in
.build_and_sign?;
let envelope = new
.identity_document
.token
.audience
.action
.build?;
let client = new;
let resp = client.evaluate_http.await?;
if resp.is_allowed
Standalone adapters (without axum)
Call the adapters directly in any async or sync context:
// HTTP (sync)
use ;
use Utc;
let sink = new;
let response = handle_http_json_request;
// response.status_code, response.body["allowed"]
// MCP
use handle_mcp_jsonrpc_request;
let response = handle_mcp_jsonrpc_request;
// A2A
use handle_a2a_request;
let response = handle_a2a_request;
Host context vs request runtime context
runtime_context in RequestEnvelope is caller-provided data used for request-specific checks (spend amount, target email/calendar, etc).
Security-sensitive trust signals (delegation depth, cognitive/reputation/risk assessments, extra approvals, clock leeway) are supplied by your infrastructure via HostContext/HostContextProvider and are never trusted from inbound request JSON.
Trust state
Sync (suitable for single-process / CLI use):
use ;
use Arc;
// In-memory with interior mutability — share as Arc<InMemoryTrustState>
let state = new;
state.revoke_token?;
state.emergency_deny_agent?;
state.revoke_tokens?;
state.clear_emergency_deny_list?;
state.flush_expired_nonces?;
// File-backed (advisory lock, CLI / single-process only)
let state = new;
Async (Redis for production):
use RedisTrustStateStore;
let state = new;
// revoke_tokens uses a Redis pipeline; clear_emergency_deny_list uses SCAN+DEL
Revocation and control plane
use ;
let state = new;
// Revoke with an auditable receipt
let op = revoke_token_with_receipt?;
println!;
Trust pipeline
Every evaluation runs these stages in order, fail-closing at the first failure:
normalize_request— parse and contract-validate the request envelopevalidate_profile_compatibility— SPIFFE / OIDC / Developer profile checksverify_signatures— Ed25519 on identity document and delegation tokenvalidate_identity_document_lifetime— expiry with configurable clock leewayenforce_revocation_and_redelegation— revocation, emergency deny, nonce replay, delegation depthvalidate_token_lifetime— tokenissued_at/expires_atwindowvalidate_token_binding—agent_id,delegator_id, audience cross-checkevaluate_policy— allowed actions, max spend, calendar constraints, cognitive/reputation gates
Custom policy
use ;
;
// Pass to evaluate_request_with_policy / evaluate_and_audit_with_policy
CLI
# Sign an identity document
# Sign a delegation token
# Verify a request envelope offline
# Interactive grant approval
# Revoke a token (persists to ~/.delegated/trust-state.json)
Repository layout
src/
engine.rs — trust evaluation orchestration
stages.rs — individual evaluation stages
policy.rs — built-in policy checks
revocation.rs — TrustStateStore/Admin traits + InMemoryTrustState + FileBackedTrustState
revocation_async.rs — AsyncTrustStateStore/Admin + InMemoryAsyncTrustState
revocation_redis.rs — RedisTrustStateStore (feature: redis)
issuance.rs — DelegationTokenBuilder + AgentIdentityDocumentBuilder + RequestEnvelopeBuilder
adapters/
http.rs — HTTP adapter
mcp.rs — MCP JSON-RPC adapter
a2a.rs — A2A adapter
axum_layer.rs — Tower Layer middleware (feature: axum)
guard.rs — rate limit + concurrency guard
client.rs — DelegatedClient (feature: client)
audit.rs — AuditSink trait + JsonlFileAuditSink
discovery.rs — DiscoveryService + JWKS handlers
control_plane.rs — revocation receipts + operational reports
crypto.rs — signing + verification primitives
tests/
conformance.rs — end-to-end allow/deny/replay/revocation
interop_harness.rs — cross-adapter and cross-profile parity
reference_cli.rs — CLI signing/verification/approval workflows
integration_server.rs — real axum server + DelegatedClient round-trips
Testing
# Core tests
# Integration tests (requires axum + client features)
# With all optional features
License
Licensed under either MIT or Apache-2.0 at your option.