Skip to content

What Caracal Does

Caracal enforces authorization before an agent acts, not after. This page explains how that enforcement works, what it produces, and how it differs from conventional middleware approaches.

AI agents and autonomous workflows need access to tools, APIs, and data. Giving them long-lived credentials causes two problems: you cannot know what the agent will do with them before it acts, and you cannot revoke access granularly once something goes wrong.

Caracal addresses both problems by issuing a mandate — a short-lived, scoped JWT — only after an OPA policy evaluation determines the requested access is allowed. The agent receives a credential only if the policy explicitly permits it, and that credential expires in minutes, not days.

The Security Token Service (STS) is the enforcement hub. Every agent that wants to call a tool or API must first exchange credentials with the STS for a mandate. The STS does this before issuing any token:

  1. Receives an exchange request carrying the agent’s application credentials and a list of resources it wants to access.
  2. Loads the active policy set for the zone the agent belongs to.
  3. Calls OPA with a structured input containing the principal, resource, action, session state, and delegation chain.
  4. Only if OPA returns decision = "allow" with evaluation_status = "complete" does the STS sign and return a mandate.
  5. Emits an audit event for every resource evaluation, whether allowed or denied.

If no policy set is active in the zone, the STS installs a deny-all fallback — no agent can exchange credentials until a policy is activated. There is no default-allow state.

A mandate is an ES256-signed JWT. The claims it carries go beyond standard OAuth tokens:

ClaimPurpose
subApplication identity of the agent
zone_idZone this token is bound to
scopeOAuth scopes the agent was granted
targetArray of resource identifiers the token is valid for
sidSession ID binding the token to a specific agent session
agent_session_idID of the agent session in the Coordinator
delegation_edge_idID of the delegation edge, if this agent was delegated to
delegation_chainFull chain of sessions from root to this agent
hop_countNumber of delegation hops
expExpiry (15 minutes for per-call tokens, 60 minutes for ambient tokens)
jtiUnique token ID for replay protection

Two token types exist:

  • Ambient tokens (use = "ambient") are issued when an agent starts a session. They carry the agent’s identity and can be re-presented to the STS to exchange for narrower per-call tokens bound to a specific resource. TTL: 60 minutes.
  • Per-call tokens (use = "per-call") are the tokens an agent presents to the Gateway or a resource. They are scoped to specific resources and cannot be re-used as a subject token for further exchange. TTL: 15 minutes.

When an agent calls an MCP tool or upstream API, the request passes through the Gateway. The Gateway:

  1. Validates the mandate’s signature against the zone’s JWKS endpoint.
  2. Checks the JTI for replay (each JTI is accepted only once).
  3. Confirms the resource being accessed matches a binding registered for that upstream.
  4. Optionally substitutes a provider OAuth token or API key for the upstream call — the agent never holds those credentials directly.

The agent presents its mandate; the Gateway handles the actual credential presented to the upstream. This is credential brokering: agents hold short-lived mandates, not provider secrets.

An agent can delegate a subset of its authority to another agent by creating a delegation edge in the Coordinator. Delegation is:

  • Graph-tracked: edges are stored and traversed in the database; cycle detection prevents loops
  • Caveat-constrained: edges carry TTL, hop count, budget, and scope limits
  • Cascading on revocation: revoking an edge terminates all downstream edges and agent sessions in a single operation

When a delegated agent exchanges for a mandate, the STS validates the full delegation chain and embeds it in the JWT. A resource can inspect the chain to understand the full lineage of the agent that called it.

Every token exchange and OPA decision produces an AuditEvent emitted to a Redis stream (caracal.audit.events). The Audit service consumes this stream and writes events to a PostgreSQL append-only table. Events include:

  • The OPA decision (allow or deny)
  • The evaluation status and determining policies
  • The OPA diagnostic output
  • The policy set version and manifest SHA that produced the decision
  • A chain HMAC over consecutive events, enabling tampering detection

Nothing is ever updated or deleted in the audit table. Querying the audit trail is available through the TUI and CLI (audit tail, explain).

Caracal does not replace your LLM framework, agent scheduler, or prompt router. It sits alongside those systems as an authorization layer. An agent calls Caracal’s SDK to get a mandate, and then uses that mandate when calling tools through the Gateway or directly to resources that verify it. Caracal does not inspect or filter the content of tool calls — it enforces whether the call is permitted to happen at all.

Read Installation to install the CLI and bring up the stack, or skip to Key Ideas at a Glance for a condensed reference of the full model.