SPIFFE for who. OpenFGA for what. Token exchange for when. One bootstrap call for all of it.
Draco is an authentication and authorization system for AI agents. It brokers authentication (the agent never holds long-lived credentials; Draco acquires identity and tokens on its behalf) and orchestrates authorization (querying the authorization provider on every tool call and enforcing the result). Stop managing credentials; start managing policy.
Giving an agent an identity says who it is. It does not say what it may do, on whose behalf, against which tool. Most agent security fills that gap from the outside only: a proxy or firewall the agent discovers by hitting it. Draco enforces from the outside and informs from the inside. Every tool call is checked against policy at the moment of the call, and the same compiled policy is injected into the agent's reasoning context (system prompt and tool list), so the agent plans within its constraints instead of colliding with them. When it violates policy anyway, its trust level drops, it keeps less access, and the drop persists until an administrator restores it. The result is an agent that is identity-bearing, policy-aware, self-regulating, and measurable.
Draco is an in-process Python library. There is nothing else to deploy: your agent imports draco, and every identity, token, and authorization operation happens inside the agent's process against your existing infrastructure.
sequenceDiagram
participant Agent as Agent process (your code + draco)
participant SPIRE
participant IdP as OAuth IdP
participant AuthZ as OpenFGA or local bundles
participant Tool as Tool backend
note over Agent,IdP: bootstrap(), once
Agent->>SPIRE: fetch SVID (Workload API)
Agent->>IdP: SVID assertion, base token back
note over Agent,Tool: every tool call
Agent->>AuthZ: guard(tool) at current trust level
AuthZ-->>Agent: allow, or deny (deny degrades trust)
Agent->>IdP: RFC 8693 exchange, per-tool token back
Agent->>Tool: call with audience-bound, scope-bounded token
Draco integrates with, and deliberately does not replace: an identity issuer (SPIRE, or anything producing SPIFFE SVIDs), an OAuth IdP supporting token exchange (such as Keycloak), an authorization provider (OpenFGA) or compiled policy bundles, and optionally OpenBao for persistent trust state. Draco does not issue identity, make authorization decisions, or store credentials.
draco-toolkit (draco.core.*): a framework-agnostic Python toolkit agents import directly. Identity via SPIFFE, per-tool OAuth tokens via RFC 8693 exchange, per-call authorization, posture management, and behavioral telemetry. Each piece is usable on its own; nothing forces you to adopt the whole stack.
This release supports agents talking directly to their backing services: SPIRE for identity, your IdP for tokens, and either a live OpenFGA store or compiled local policy bundles for authorization, selected by one config switch.
pip install draco-toolkitRequires Python 3.12+. The import name is draco (from draco.core.bootstrap import bootstrap). Optional extras: pip install "draco-toolkit[metrics]" for OpenTelemetry instrumentation.
Draco is configured by one JSON file (connectivity: where SPIRE, the IdP, and the authorization source live) plus policy bundles (authorization: which tools are allowed at which trust level).
What you need: a SPIRE agent socket for identity and an OAuth IdP that supports token exchange (such as Keycloak) for tokens. In bundle mode, authorization resolves from local files, so no authorization server is required. No infrastructure at hand yet? The testing-without-infra guide exercises the whole surface with in-memory fakes.
With those in place, securing a tool call is:
from draco.core.bootstrap import Mode, bootstrap
from draco.core.tools import add_posture, call_tool_backend, get_tools_from_bundle, guard, tool_token
async with bootstrap(Mode.DIRECT, "draco-config.json") as components:
# Intrinsic: put the agent's compiled policy into its reasoning context.
system_prompt = add_posture("You are a research assistant.")
# Construction-time filter: only bind tools the agent may use right now.
tools = get_tools_from_bundle()
# Per tool call: authorize, mint a scoped token, dispatch (HTTP or MCP).
await guard("web_search")
token = await tool_token("web_search")
result = await call_tool_backend("web_search", "search", {"q": "spiffe"}, token)guard() enforces the authorization decision: on deny it raises ToolCallError, records the violation to the observer, and degrades the agent's trust level (the degradation persists across restarts and requires administrative restoration; infrastructure errors fail closed without degrading trust). tool_token() exchanges the agent's identity for a token whose audience is one tool backend and whose scope is exactly the granted operations; a denied tool never yields a token.
You keep your agent framework. Draco returns plain tool definitions and strings, and guard()/tool_token() are called inside ordinary tool functions; hello-agent is a complete working agent showing the wiring for LangGraph + A2A against live infrastructure. The full walkthrough, including the SPIRE and IdP setup, is in getting started.
- Identity brokering. X.509 and JWT SVIDs from the SPIRE Workload API, with automatic rotation. The agent never manages certificates.
- Layered tokens. A base token proves identity to the IdP via SVID assertion (IdP differences are handled in configuration, not code); per-tool tokens are minted on demand via RFC 8693 exchange, audience-restricted and scope-bounded by the live grant, cached, cleared on trust degradation, and revoked at shutdown.
- Per-call authorization. Every tool call is checked at the agent's current trust level, against a live OpenFGA store or local compiled bundles behind the same interface.
- Intrinsic policy. The compiled policy brief is injected into the agent's context, and the tool surface the model sees is filtered to what is actually permitted, so the agent plans within policy instead of discovering walls.
- Trust model. Two tracked dimensions (
policy_compliance, behavioral;content_trust, provenance) degrade monotonically and persist; the derivedtrust_levelkeys every authorization decision. - Telemetry. An observer records per-session action sequences, scope compliance, and trust trajectory for downstream alignment measurement.
- Transports. Tool backends over HTTP or MCP (full streamable-HTTP lifecycle), with an endpoint guard that refuses to send bearer tokens to non-https or non-allow-listed destinations.
The documentation lives in docs/: seven concept pages (start with how Draco works), reference pages for every module, and task-oriented guides. The architecture and design-decision record live in the companion draco-docs repository.
python/ The draco package (draco.core.*)
docs/ Developer documentation
hello-agent/ Reference agent: full SDK integration, LangGraph + A2A
tool-backend/ Reference tool backends (MCP server, HTTP service) with OAuth middleware
deploy/ Kubernetes manifests (sanitized samples)
Apache License 2.0, copyright Draco Tech. See LICENSE.