Skip to main content

Verifiable, identity-rooted delegation tokens for AI agents.

Project description

Agent Passport

Verifiable, identity-rooted delegation tokens for AI agents — built on existing standards (OIDC, OAuth 2.0 Token Exchange, JWT, NIST SP 800-63-3 assurance levels).

Status: v0 alpha. Library, CLI, and three runnable examples work end-to-end against a hermetic mock OIDC provider. Live CSP integration needs your CSP_* configuration in .env.

Why

When a user tells an AI agent "do X on my behalf," there is no standard, verifiable way for a downstream tool, MCP server, or another agent to know:

  1. Who the principal is (and how strongly that identity was proofed),
  2. What authority the agent was actually granted,
  3. For how long the grant is valid,
  4. What chain of delegation got us here (user → agent A → agent B → tool C).

Most agent frameworks paper over this with bare API keys. Agent Passport closes the gap with short-lived, scope-bound, NIST-identity-rooted delegation tokens that downstream verifiers check cryptographically — with chain attenuation enforced at issuance and re-checked at verification.

This project is a concrete contribution to the NIST AI Agent Standards Initiative and the related NCCOE Software and AI Agent Identity and Authorization project.

Install

Requires Python 3.11+.

pip install csp-agent-passport

The install registers an csp-agent-passport console script.

For local development (running the test suite, editing source), see CONTRIBUTING.md for the editable-install instructions.

Quickstart

The fastest path to seeing the full loop without any external CSP credentials is to run one of the bundled examples:

python examples/quickstart.py

That script boots an in-process mock OIDC provider, mints an ID token, exchanges it for an Agent Passport (RFC 8693), verifies it against a policy, and demonstrates two typed-error paths. Output is annotated section-by-section.

For real CSP integration, copy .env.example to .env, fill in your sandbox credentials, then drive the CLI:

csp-agent-passport login                                                  # OAuth code + PKCE; browser opens
csp-agent-passport issue \
    --agent-id agent:alice \
    --agent-model claude-opus-4-7 \
    --tool-scope 'flights:*' \
    --task-purpose 'book a flight SFO->JFK' \
    --aud https://my-mcp-server.example.com/ \
    --ttl 900 > passport.jwt

csp-agent-passport inspect < passport.jwt                                 # decode and pretty-print
csp-agent-passport verify --aud https://my-mcp-server.example.com/ \
    --require-ial 2 --required-scope 'flights:book' < passport.jwt

To delegate further (e.g., from agent Alice to agent Bob):

csp-agent-passport delegate \
    --agent-id agent:bob \
    --agent-model claude-opus-4-7 \
    --tool-scope 'flights:book' \
    --aud https://other-svc.example.com/ \
    --ttl 300 < passport.jwt > child.jwt

csp-agent-passport --help lists all subcommands; each has its own --help.

Configure your CSP

Agent Passport works with any OIDC + PKCE provider via a generic CSP_* env-var namespace. Discovery-driven by design (per OIDC Discovery 1.0 / RFC 8414), so only the well-known URL is hardcoded:

Variable Purpose
CSP_DISCOVERY_URL Full URL to your CSP's /.well-known/openid-configuration.
CSP_CLIENT_ID OAuth client identifier for your registered app.
CSP_CLIENT_SECRET OAuth client secret (omit / leave blank for public clients).
CSP_REDIRECT_URI Loopback callback URL for the OAuth code flow; RFC 8252 requires http://localhost:<port> or http://127.0.0.1:<port>.
CSP_SCOPES Space-separated OIDC scopes (e.g. "openid email profile").
CSP_ACR_MAPPING Which acr → IAL/AAL/FAL mapping to use: ial (default — handles NIST 800-63-3 …/ial/N URIs plus the legacy …/loa/1 and …/loa/3 URIs that some providers still emit), or a Python import path pkg.module:func_name for a custom mapping when your CSP emits ACR URIs outside the built-in set.

For most CSPs, only CSP_DISCOVERY_URL and CSP_CLIENT_ID/SECRET need changing — the built-in ial mapping handles the common URI forms. Custom CSPs slot in via a one-function AcrMapping referenced by Python import path; no library changes needed.

CLI reference

Command Purpose
login OAuth Authorization Code + PKCE against the configured CSP (RFC 8252). Stores the ID token under $XDG_DATA_HOME/csp-agent-passport/. --id-token <jwt> skips the OAuth dance for paste-in / scripted use.
issue Mint a root Passport from the stored ID token. Flags: --agent-id, --agent-model, --tool-scope (repeatable), --task-purpose, --aud, --ttl (default 900s).
verify <token> Verify against a policy and print the verified claims as JSON. Flags: --aud (required), --require-ial/--require-aal/--require-fal, --required-scope, --issuer (repeatable). Token from arg or stdin.
inspect <token> Decode (no signature check) and pretty-print every claim, including namespaced agent claims and any chained act.
delegate <parent> Mint a child Passport from a parent (with attenuated scope). Flags: --agent-id, --agent-model, --aud, --tool-scope (repeatable), --task-purpose, --ttl (default 300s).
where Print the XDG data directory used for the ID-token store and the local issuer's signing key.

All token args read from stdin when - or absent, so the commands compose:

csp-agent-passport issue ... | csp-agent-passport delegate --aud ... --agent-id ...

Examples

File What it shows
examples/quickstart.py The full loop: login → issue → verify, plus two failure-mode demos (AudienceMismatch, IALInsufficient).
examples/multi_agent_chain.py Alice → Bob → Carol delegation; the leaf service walks the full chain, re-checking attenuation and IAL monotonicity; prints the delegation tree.
examples/mcp_middleware.py A PassportMiddleware class that wraps a tool dispatcher, enforces per-tool required_scope, and shows defense-in-depth refusal of overbroad and wrong-audience tokens. Drop-in pattern for MCP servers.
examples/langchain_tool_wrapper.py A PassportProtectedTool shape-compatible with langchain_core.tools.BaseTool. Demonstrates scope enforcement and signature-tamper detection.

Every example runs from a clean checkout against the hermetic in-process mock OIDC provider — no external creds needed:

python examples/quickstart.py
python examples/multi_agent_chain.py
python examples/mcp_middleware.py
python examples/langchain_tool_wrapper.py

How this fits

There are several adjacent open-source projects. The honest map:

  • You want a turnkey identity service (Postgres + server, real-time revocation today, DPoP, dynamic client registration) — look at ZeroID.
  • You want a pip install library to embed in an MCP middleware or LangChain tool wrapper, with NIST SP 800-63-3 IAL/AAL/FAL propagated through the delegation chain — you're in the right place.
  • You need workload identity (cryptographically attested "what runtime is this?") — look at SPIFFE/SPIRE. It composes with Agent Passport, doesn't replace it.
  • You're a security team buying a control plane (discovery, governance, dashboards) — look at the commercial NHI vendors (Aembit, Astrix, Oasis, Token, Entro). This library deliberately doesn't compete there.

See COMPARISON.md for the full write-up, including where Agent Passport is ahead, behind, or complementary.

Library use

Three primitives compose to cover every use case:

from csp_agent_passport import (
    Issuer, IssuanceRequest, DelegationRequest,
    Verifier, VerificationPolicy, InMemoryKeyStore,
    IDTokenValidator, ial_acr_mapping,
)
  • Issuer takes an OIDC-validated identity assertion (via IDTokenValidator + an AcrMapping) and mints signed delegation Passports. issue() for roots; delegate() for children (with issuer-side scope-attenuation enforcement).
  • Verifier validates a Passport against a VerificationPolicy: signature, time window with clock-skew tolerance, trusted issuer, audience exact-match, IAL/AAL/FAL floors, wildcard policy, required scope. For chained tokens, verify(token, chain=[...]) walks the chain root-first and re-checks every link.
  • IDTokenValidator validates an OIDC ID token against a CSP discovered via /.well-known/openid-configuration (no hardcoded endpoints). ial_acr_mapping is the built-in acr → IAL/AAL/FAL translation; supply your own AcrMapping for CSPs that emit non-standard URIs.

Typed exceptions inherit from AgentPassportError:

  • VerificationError branch: InvalidSignature, Expired, NotYetValid, AudienceMismatch, IALInsufficient, ScopeViolation, WildcardScopeNotAllowed, ChainBroken, MalformedClaims, …
  • IssuanceError branch: DiscoveryError, JWKSError, UnsupportedAcr, ScopeAttenuationError.

Branch on the type, not the message.

Standards

Agent Passport composes existing standards rather than inventing new ones:

  • RFC 7519 — JSON Web Token
  • RFC 7515 — JSON Web Signature
  • RFC 8693 — OAuth 2.0 Token Exchange (the act claim and nested actor chains)
  • RFC 7636 — PKCE
  • RFC 8252 — OAuth 2.0 for Native Apps (local-loopback redirect)
  • RFC 8485 — Vectors of Trust (input-side only; carried through from the CSP when emitted, but IAL/AAL/FAL numerics are the canonical assurance representation in the Passport)
  • NIST SP 800-63-3 — Digital Identity Guidelines (IAL/AAL/FAL)
  • OpenID Connect Core 1.0 and Discovery 1.0

Project layout

csp-agent-passport/
├── pyproject.toml
├── README.md
├── CLAUDE.md                              # full design context
├── .env.example                           # CSP config template
├── src/csp_agent_passport/
│   ├── claims.py                          # Pydantic Passport / AgentClaims / ActClaim
│   ├── issuer.py                          # Issuer, IssuanceRequest, DelegationRequest
│   ├── verifier.py                        # Verifier, VerifiedPassport, chain walking
│   ├── policy.py                          # VerificationPolicy
│   ├── keys.py                            # KeyStore Protocol + InMemoryKeyStore
│   ├── errors.py                          # typed exception hierarchy
│   ├── cli.py                             # Typer-based CLI
│   └── oidc/
│       ├── base.py                        # OIDCClient Protocol, AssuranceLevels, ial_acr_mapping
│       └── validator.py                   # IDTokenValidator (discovery + JWKS)
├── examples/                              # see "Examples" above
└── tests/
    ├── fixtures/mock_oidc/                # in-process OIDC provider for hermetic tests
    └── test_*.py                          # 141+ tests; full coverage of every error path

Versioning & deprecation policy

The project follows Semantic Versioning 2.0.0.

While in 0.y.z (alpha) — any release MAY contain breaking changes. Breaking changes are flagged under ### Changed (breaking) in CHANGELOG.md. Adopters should pin a specific version or version range (e.g. csp-agent-passport>=0.1,<0.2).

Once 1.0.0 ships:

  • Breaking changes require a major-version bump (1.x.y2.0.0).
  • Deprecations are announced at least one minor version before removal — so a feature deprecated in 1.4.0 cannot be removed before 2.0.0, and a feature deprecated in 1.4.0 will continue to work (with a DeprecationWarning) through every 1.x release.
  • Security fixes may ship as patch releases on supported versions without notice; see SECURITY.md for the supported-versions table.
  • The CHANGELOG's ### Deprecated section is the authoritative list of deprecated APIs and their planned removal versions.

Governance: see GOVERNANCE.md. Candidate next steps: see ROADMAP.md.

Development

pip install -e '.[dev]'

pytest                                     # full suite, hermetic
pytest --cov=csp_agent_passport --cov-report=term-missing
ruff check . && ruff format --check .
mypy                                       # --strict, covers src/ + tests/

The test suite is fully hermetic (the mock OIDC provider runs in-process on a random port) — no creds or network needed.

See CLAUDE.md for the design context behind every decision in this codebase: the trust model, why each RFC is used, security guardrails, and the suggested order of work.

License

Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

csp_agent_passport-0.2.1.tar.gz (100.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

csp_agent_passport-0.2.1-py3-none-any.whl (41.1 kB view details)

Uploaded Python 3

File details

Details for the file csp_agent_passport-0.2.1.tar.gz.

File metadata

  • Download URL: csp_agent_passport-0.2.1.tar.gz
  • Upload date:
  • Size: 100.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for csp_agent_passport-0.2.1.tar.gz
Algorithm Hash digest
SHA256 d5404b797ddd18c3ac974a8d035c5e0188f65793cf1552a992a6b4a10ded530d
MD5 053308e47b4bc1fa2a1d44e00bb0ec2f
BLAKE2b-256 382639699581208345a55d019e5ba6ada8d2fe770d248663834181f516642fcb

See more details on using hashes here.

Provenance

The following attestation bundles were made for csp_agent_passport-0.2.1.tar.gz:

Publisher: release.yml on antspriggs/csp-agent-passport

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file csp_agent_passport-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for csp_agent_passport-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ab36e74a24d4d3dec89212e2c49f894521e9cca5168e6dd9256266f6063ce989
MD5 1a8f2f18f948265afb01d5bb4e1b5716
BLAKE2b-256 42f58092f1ee843ae92ac72bd2ad147460f8757498461f8ea5e0e4f946b608c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for csp_agent_passport-0.2.1-py3-none-any.whl:

Publisher: release.yml on antspriggs/csp-agent-passport

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page