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 Vectors of Trust).

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 nist-agent-passport

The install registers a nist-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:

nist-agent-passport login                                                  # OAuth code + PKCE; browser opens
nist-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

nist-agent-passport inspect < passport.jwt                                 # decode and pretty-print
nist-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):

nist-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

nist-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/nist-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:

nist-agent-passport issue ... | nist-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

Library use

Three primitives compose to cover every use case:

from nist_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:

Project layout

nist-agent-passport/
├── pyproject.toml
├── README.md
├── CLAUDE.md                              # full design context
├── .env.example                           # CSP config template
├── src/nist_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

Development

pip install -e '.[dev]'

pytest                                     # full suite, hermetic
pytest --cov=nist_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

nist_agent_passport-0.1.0.tar.gz (79.8 kB view details)

Uploaded Source

Built Distribution

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

nist_agent_passport-0.1.0-py3-none-any.whl (39.6 kB view details)

Uploaded Python 3

File details

Details for the file nist_agent_passport-0.1.0.tar.gz.

File metadata

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

File hashes

Hashes for nist_agent_passport-0.1.0.tar.gz
Algorithm Hash digest
SHA256 25a26ce9b59b20bb2f6f7f01b2714afb777dc318a501bd90d5c2e29550e715ac
MD5 386ae8b5001ef66b38da9c9ec9b1d1e2
BLAKE2b-256 e650755b401f0be491e6c1318c37c5bde2f1e25bf8e6618840ab4fc8caf652e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for nist_agent_passport-0.1.0.tar.gz:

Publisher: release.yml on antspriggs/nist-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 nist_agent_passport-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for nist_agent_passport-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 80a3676306c9b5db3ddf23d2937a6eeccc4bb92553021b7323566c861c19e97e
MD5 c576b541a68a7fb54a71b15f2e0d365c
BLAKE2b-256 c1ad3450aaeb782bc486302d4622e60c17e176f3dc6dbd33c3577ca15f00c182

See more details on using hashes here.

Provenance

The following attestation bundles were made for nist_agent_passport-0.1.0-py3-none-any.whl:

Publisher: release.yml on antspriggs/nist-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