AgentPAM.ai

Architecture

Token chain, policy, audit

This page is for the engineers and security architects who have to evaluate us. All internal authorization context rides on standard claim names — inventing claims would break your existing token validators and SIEM parsing rules.

Token chain · RFC 8693

Four-step token exchange

The whole chain is delegation semantics only — never impersonation. Every access carries the human subject and the agent subject as two independent identities. Impersonation destroys the audit chain.

token-ladder.txtscrolls horizontally
[1] Human -> your IdP
    OIDC. The human's id/access token = Tu.
    TTL ~1h -- their policy, not ours.

[2] Agent -> AgentPAM /token                        RFC 8693 token exchange
    grant_type    = urn:ietf:params:oauth:grant-type:token-exchange
    subject_token = Tu                     <- the human (delegation, NOT impersonation)
    actor_token   = agent instance assertion
    resource      = <upstream API>         RFC 8707 resource indicators
    authorization_details = [{             RFC 9396 rich authorization requests
        type: "agent_task",
        task_id, purpose, sensitivity,
        lifecycle_binding: { task_id, termination_states }
    }]
    --> Ts : session token. TTL 5-15 min. cnf.jkt (DPoP-bound).
        claims:
          sub  = the human
          act  = { sub: agent_instance_id, act: { ...upstream hop... } }
          agent_blueprint_id            audit only -- never a policy input
          agent_session_id, task_id, sponsor
          scope                         already narrowed

[3] Gateway -> AgentPAM /token
    subject_token = Ts
    --> Tup : upstream credential. TTL 60-300s. Header-injected.
        *************** THE AGENT NEVER SEES THIS ***************

[4] Sub-agent delegation
    Repeat [2] with Ts as the subject_token.
    scope MUST be a strict subset. Monotonic attenuation. act chain nests.
C-05 · delegation, not impersonation

Two subjects, all the way down

sub is always the human; the act chain carries the agent instance and upstream hops. An audit line has to read “Alice, via Claude Code session X, during task Y, at time T” — not “a bearer token called GitHub.” An autonomous agent omits subject_token, in which case sub is the agent instance and accountability rests on the sponsor claim.

C-06 · sender-constrained

Why DPoP rather than mTLS

The gateway terminates TLS, which breaks mTLS binding on the agent → gateway leg. DPoP (RFC 9449) signs per request at the application layer and survives the gateway. Bare bearer tokens are prohibited: the goal is to make a stolen token waste paper.

TTL design

The TTL ladder is asymmetric, and that is deliberate

TokenTTLBindingWhy this number
Tu~1hYour IdP decidesYour policy, not ours. We only consume the assertion.
Ts5–15 minDPoP (cnf.jkt)DPoP-bound and revocation-checked against the PDP on every call, so a stolen copy is unusable without the private key — which is why it can tolerate a relatively long life.
Tup60–300 sNone (upstream API's format)An unbound upstream credential is the highest-value thing on the entire chain and works for whoever holds it. So it must be the shortest-lived, and it is never written to disk.
Ts′≤ parent TTLDPoPA sub-delegation may be neither longer-lived nor broader.
lifecycle_binding

Credential lifetime bound to task state, not to the clock

lifecycle_binding: {task_id, termination_states[]} — the moment the task reaches a terminal state, every credential on that chain is void without waiting for the TTL. This lands directly on the “long-running agent holds too much privilege” question every security team asks.

Monotonic attenuation

A sub-agent cannot out-scope its parent

Agent-to-agent privilege escalation is a named requirement in standards-body work, and the drafts require mandatory attenuation — but as far as we know no shipping product enforces it end to end. We enforce scope(child) ⊂ scope(parent) in the broker and refuse any exchange that exceeds it.

Policy

Three levels of granularity; the differentiation is at parameter level

Deny by default: any tool call not explicitly permitted by policy is refused, and fail-open is prohibited.

LevelExampleAssessment
Server levelthis agent may reach the Stripe MCP serverTable-driven and simple. Also the level per-tool JIT collapses to in practice — which is an attackable seam.
Tool levelallow refund · deny payoutglob / regex, deny by default. Most shipping gateways stop here.
Parameter level ←differentiationrefund.amount ≤ 500 · db.query restricted to a read-only replicaRFC 9396's authorization_details is the right container, and we define the schema. Real PAM granularity lives here, not in “may it connect.”
AuthZEN

PDP API

The OIDF AuthZEN working group's PDP interface. We implement it, which is what lets us be registered as an external authorizer for your existing gateway.

COAZ

MCP tool authorization profile

As far as we know the only standards-body work aimed at MCP tool authorization, mapping tool calls onto a Subject-Action-Resource-Context model.

AARP

Can return “what is still missing”

Lets the PDP return what preconditions must be satisfied (approval, consent, delegated authorization, attestation, risk assessment) instead of a flat denial. This is the primitive that expresses human-in-the-loop as a standard.

Human in the loop

What actually kills approval workflows is frequency

A few hundred prompts an hour guarantees rubber-stamping. Any human-in-the-loop design that does not solve frequency first is just manufacturing compliance theatre.

  1. No prompt by default. Policy has to cover the overwhelming majority of calls; only operations explicitly marked high-sensitivity escalate. The prompt is the exception path, not the main path.
  2. Out-of-band approval, not a blocking dialog. Use CIBA (OIDC Client Initiated Backchannel Authentication) to push to a phone or Slack while the agent suspends and waits. There is a protocol-layer answer to this; it has just never been wired to a local MCP gateway.
  3. The unit of approval is the task, not the call. A human approves “this permission bundle for this task,” not each individual API call. That is exactly what lifecycle_binding is for.
  4. Measure approval fatigue. The Portal monitors approval rates; a rate approaching 100% is a rubber-stamp signal and triggers a policy-refactor recommendation. We make our own failure mode a metric.

Audit

The unit of audit is the task, not the API call

Classic PAM session recording fails completely here, and not only because there is no session. There is a more fundamental reason.

The root causeThe transcript that explains the action lives in the client, not on the wire. You cannot record “why” at the gateway. So audit has to actively collect intent (task declaration, purpose, sensitivity) rather than passively record traffic.
authorization-decision-eventscrolls horizontally
// A normalized agent authorization decision event.
// Emitted to any SIEM (syslog / file / Kafka -- local, no cloud assumed).
// Correlated to OTel gen_ai.* spans via W3C Trace Context.
{
  human_subject      : "[email protected]",      // who is accountable
  agent_identity     : "ai-000-3f9c",              // which registered instance
  agent_blueprint    : "bp-claude-code-2.x",        // what kind of agent
  sponsor            : "[email protected]",      // mandatory human guarantor
  task               : { id, purpose, sensitivity },
  tool               : "stripe.refund",
  resource           : "https://api.stripe.com",
  decision           : "deny",
  obligations        : ["step_up_ciba"],            // not a flat refusal
  delegation_chain   : [ human -> agent -> sub_agent ],
  binding            : { method: "dpop", jkt },
  traceparent        : "00-4bf92f...-00f067...-01", // W3C Trace Context
  ts                 : "2026-07-21T09:14:02.118Z"
}
Why define our own: OCSF currently has no agent class; OpenTelemetry GenAI covers observability but not authorization decisions; each IdP's schema is proprietary and only usable inside its own system. This space is empty, and it is exactly what auditors ask for. Contributing it back to OCSF is a very cheap credibility investment.
C-08 · tamper-evident and attributableAny logging design that cannot answer “which person's which agent did this, for what task” does not meet the bar. That is not our preference — it is the common requirement of SOC 2 CC6.1 / CC6.6, PCI DSS Req.8, and ISO 27001 A.8.15. See the compliance mapping

Gateway compatibility

Gateway compatibility matrix

This table is measured, 2026-07: 12 gateways, source review plus a runtime execution of agentgateway. Only 4 cleanly support external AS delegation. We previously wrote “any conformant gateway can already do this” — that was false and has been removed.

GatewayPrimary / external AS delegationCo-primary / external PDP (can mutate headers)stdioSelf-host / air-gap
Solo.io agentgateway✓✓ Runtime-proven✓ Supported
extAuthz http+grpc
✓ Supported
native
✓ Supported
IBM ContextForge✓ Supported
per-server, arbitrary URL
✓ Supported
OPA/Cedar, mutates headers
✕ Not supported
needs translate sidecar
✓ Supported
Kong AI Gateway✓ Supported
Enterprise only
✓ Supported
Enterprise opa
✕ Not supported⚠ Conditional
AWS Bedrock AgentCore✓ Supported
discoveryUrl pattern is .+
⚠ Conditional
interceptor, Lambda ARN only
✕ Not supported
endpoint must be https://
✕ Not supported
AWS only
Envoy / Istio⚠ Conditional
arbitrary issuer yes, PRM is a static file you author
✓ Supported
best-in-class ext_authz
✕ Not supported✓ Supported
Azure APIM⚠ Conditional
arbitrary issuer yes, PRM hand-written
⚠ Conditional
DIY, fail-open risk
✕ Not supported⚠ Conditional
needs Azure
Pomerium✕ Not supported
hardcoded to r.Host
✕ Not supported
it is the PDP itself
✕ Not supported✓ Supported
Obot✕ Not supported
hardcoded h.baseURL
✓ Supported
webhook, mutates body
✓ Supported
container-wrapped
✓ Supported
MintMCP✕ Not supported
MintMCP is the AS
⚠ Conditional
sandboxed JS, not a PDP callback
✓ Supported✕ Not supported
SaaS
Cloudflare MCP Portals✕ Not supported
Access is always the AS
✕ Not supported✕ Not supported
explicitly unsupported
✕ Not supported
SaaS
Docker MCP Gateway✕ Not supported
client-side discovery only
⚠ Conditional
before:http: cannot mutate headers
✓ Supported
native
⚠ Conditional
Traefik✕ Not supported
OSS has no JWT middleware
✓ Supported
ForwardAuth
✕ Not supported✓ Supported

The co-primary path (external PDP) covers far more gateways than AS delegation does, and it is healthy — Envoy/Istio's ext_authz is best-in-class, alongside Kong OPA, ContextForge plugins, Obot webhooks, and agentgateway extAuthz. All but Obot can mutate headers on allow — which is exactly the credential-injection primitive. So the honest pitch is “two viable integration paths, one of which covers most gateways”, not “the spec forces everyone to us”.

Measured: one YAML block, zero code, zero SDKOn agentgateway v1.4.0-alpha.2 (darwin-arm64) we pointed a spec-conformant gateway at AgentPAM, and the entire integration was a single mcpAuthentication config block — the gateway then published us as its authorization server and issued a correct RFC 9728 challenge. Zero code, zero SDK, one config block. It was the only one of the 12 we could execute natively on this host, so it is also the only path proven at runtime — the rest are source-review conclusions.
One more problem we have to solve alongside thisRoughly 85% of MCP servers are stdio child processes, launched by fork + pipe, with no authentication and no network. Any gateway that only governs remote HTTP is structurally blind to the dominant case. So the complete answer is a two-point deployment: an on-host component that intercepts stdio, strips credentials from the server's environment, and forwards to the broker; and a broker that authenticates the human, authorizes the specific call, injects a just-in-time credential the agent never sees, and writes the audit record. The first alone is a guardrail; the second alone is bypassed by local stdio. Only together are they a control.

Roadmap

Discovery first, enforcement second

More than half of CISOs cannot count the agents in their own environment. Nobody buys enforcement for a population they cannot count.

PhaseGoalKey deliverablesAcceptance criteria
V1 wedgeDiscovery and attributionCollector + read-only Portal views + auditor-ready reportOne docker run produces the report with no outbound access at any point; output is “N agents, what each holds, what they touched last week, which are unattributable under SOC 2 CC6”
V1.5 enforcementTier 0 + Tier 1PDP + credential broker + primary-path integrationCredentials no longer reach the agent; per-tool authorization in force; P99 latency < 200ms
V2 moatLocal attestation + cross-cloudLocal Attestor + CAEP loop + multi-IdPProcess attestation usable; revocation latency ≤ one Ts TTL
V2+ EnterpriseTier 3eBPF / Endpoint Security Framework enforcementAnswers the “non-MCP actions” competitive attack
Why this orderA read-only report has zero blast radius, POCs extremely fast, and produces a forwardable document that alarms a CISO. Doing enforcement first means going head-to-head with the incumbent IdP on day one — a fight we do not need to pick.