AI News HubLIVE
站内改写4 min read

Proveyouragent: Cryptographic identity for AI agents (Ed25519 and DPoP)

Proveyouragent is a Python library that provides cryptographic identity for AI agents using Ed25519 key pairs and DPoP (RFC 9449) request signing, ensuring every request originates from a legitimate agent. It solves agent authentication, authorization, and replay attack prevention.

SourceHacker News AIAuthor: lujainkhalil

Notifications You must be signed in to change notification settings

Fork 0

Star 0

BranchesTags

Open more actions menu

Folders and files

NameName

Last commit message

Last commit date

Latest commit

History

2 Commits

2 Commits

examples

examples

proveyouragent

proveyouragent

tests

tests

.DS_Store

.DS_Store

.gitignore

.gitignore

README.md

README.md

pyproject.toml

pyproject.toml

Repository files navigation

Cryptographic identity for AI agents.

proveyouragent gives each agent a keypair, a signed identity document, and a way to prove on every request that the request actually came from that agent. Services verify agent requests before processing them. Stolen tokens are useless without the private key.

Built on Ed25519, OAuth 2.0 Dynamic Client Registration (RFC 7591), and DPoP (RFC 9449).

The problem

AI agents call APIs, read databases, write files, and send emails. Most do this with a hardcoded service account token or a borrowed user credential. There is no standard way for a service to know:

which agent made a request

who owns and is accountable for that agent

what the agent is actually allowed to do

whether the request was replayed from a stolen token

proveyouragent solves this with a small set of primitives that compose together.

Install

pip install proveyouragent

Quick start

Give your agent an identity:

from proveyouragent import generate_keypair, save_keypair, create_software_statement

key = generate_keypair() save_keypair(key)

statement = create_software_statement( private_key=key, operator_domain="acme.com", agent_name="billing-agent", agent_version="1.0.0", scopes=["invoices:read", "payments:write"], )

Sign every request:

from proveyouragent import create_dpop_proof

proof = create_dpop_proof(key, method="GET", uri="https://api.acme.com/invoices")

response = httpx.get( "https://api.acme.com/invoices", headers={ "X-Agent-Statement": statement, "X-Agent-DPoP": proof, } )

Verify on the server:

from fastapi import FastAPI, Request from proveyouragent.middleware import AgentIDMiddleware, verify_agent

app = FastAPI()

app.add_middleware(AgentIDMiddleware, get_public_key=my_key_resolver)

@app.get("/invoices") def list_invoices(request: Request): agent = verify_agent(request, required_scope="invoices:read") return {"agent": agent.agent_name, "invoices": [...]}

How it works

Agent identity

Every agent gets an Ed25519 keypair. The private key never leaves the agent. The public key is published at a well-known URL so any service can verify requests without calling home.

The agent's identity document is a signed JWT called a software statement. It declares who owns the agent, what the agent is allowed to do, and where to find the public key.

statement = create_software_statement( private_key=key, operator_domain="acme.com", # who is accountable for this agent agent_name="billing-agent", agent_version="1.0.0", scopes=["invoices:read"], model="claude-sonnet-4-6", # optional prompt_hash="sha256:abc123", # optional, for version tracking )

Request signing with DPoP

Bearer tokens can be stolen and replayed. DPoP (RFC 9449) binds each token to the agent's private key. Every request includes a fresh proof signed by the key, covering the HTTP method and URI. A stolen token is useless without the private key.

proof = create_dpop_proof( private_key=key, method="GET", uri="https://api.acme.com/invoices", )

Verification

The service checks four things on every request:

The software statement signature is valid

The software statement has not expired

The agent has the required scope

The DPoP proof is fresh, matches this request, and has not been used before

from proveyouragent import verify_agent_request, VerifiedAgent, VerificationError

result = verify_agent_request( software_statement=statement, dpop_proof=proof, method="GET", uri="https://api.acme.com/invoices", operator_public_key=public_key, required_scope="invoices:read", )

if isinstance(result, VerifiedAgent): print(result.agent_name) # billing-agent print(result.operator_domain) # acme.com print(result.scopes) # ['invoices:read']

FastAPI middleware

The middleware handles verification automatically on every route. Verified agent details are attached to request.state.agent.

from proveyouragent.middleware import AgentIDMiddleware, verify_agent

def get_public_key(operator_domain: str):

Return the Ed25519PublicKey for this operator

Fetch from your database, config, or key registry

return your_key_store.get(operator_domain)

app.add_middleware( AgentIDMiddleware, get_public_key=get_public_key, exclude_paths=["/health", "/docs"], )

@app.get("/invoices") def list_invoices(request: Request): agent = verify_agent(request, required_scope="invoices:read") return {"invoices": [...]}

Delegation chains

Orchestrator agents can delegate a subset of their permissions to sub-agents. The chain is cryptographically linked. Scopes can only shrink as they pass down the chain.

from proveyouragent.delegation import create_root_mandate, create_delegation, verify_delegation_chain

Human authorises orchestrator

root = create_root_mandate( private_key=operator_key, operator_domain="acme.com", human_principal="[email protected]", scopes=["invoices:read", "payments:write"], agent_id="acme.com/orchestrator", )

Orchestrator delegates a subset to sub-agent

delegation = create_delegation( delegator_key=orchestrator_key, delegator_statement=orchestrator_statement, delegate_agent_id="acme.com/summariser", delegate_public_key_b64=summariser_pub_key, scopes=["invoices:read"], # subset of parent scopes only parent_token=root, human_principal="[email protected]", )

Tool verifies the full chain

result = verify_delegation_chain( token=delegation, required_scope="invoices:read", get_public_key=key_resolver, )

print(result.human_principal) # [email protected] print(result.delegate_agent_id) # acme.com/summariser print(result.depth) # 1

Scope escalation is rejected immediately:

This returns a DelegationError, not a token

create_delegation(..., scopes=["invoices:read", "admin:delete"])

DelegationError: Cannot delegate scopes not present in parent token: {'admin:delete'}

Replay cache

The default replay cache is in-memory. It works for single-process deployments but will not survive a restart or work across multiple processes.

For production, use Redis:

from proveyouragent.cache import RedisCache from proveyouragent.middleware import AgentIDMiddleware

app.add_middleware( AgentIDMiddleware, get_public_key=get_public_key, cache=RedisCache(url="redis://localhost:6379"), )

Or pass a cache directly to verify_agent_request:

from proveyouragent.cache import RedisCache

cache = RedisCache(url="redis://localhost:6379")

result = verify_agent_request( ..., cache=cache, )

What gets verified on every request

Check What it catches

Software statement signature Forged or tampered identity documents

Statement expiry Stale tokens

Scope enforcement Agents claiming permissions they were not granted

DPoP proof signature Requests not made by the key holder

DPoP method and URI binding Proofs reused on a different endpoint

DPoP freshness Old proofs being replayed

DPoP jti uniqueness Exact replay of a captured request

Running the examples

Terminal 1: start the server

uvicorn examples.server:app --reload

Terminal 2: run the client

python examples/client.py

Running the tests

pytest tests/ -v

Design decisions

Ed25519 only. No algorithm negotiation. Ed25519 is fast, has small keys, and has no known weaknesses. Supporting multiple algorithms adds complexity and attack surface.

No blockchain, no DID infrastructure. DNS is the trust anchor. Operators publish their public key at a well-known URL on their domain. Every developer already knows how DNS works.

Errors as values, not exceptions. verify_agent_request returns a VerifiedAgent or a VerificationError. No try/except needed in normal usage. The error always includes a human-readable reason.

Replay cache is pluggable. The default in-memory cache works for development. Redis works for production. Any backend that implements ReplayCache works.

License

MIT

About

Cryptographic identity for AI agents: Ed25519 keypairs, DPoP request signing, delegation chains.

Topics

security

authentication

multi-agent

ai-agents

Resources

Readme

Uh oh!

There was an error while loading. Please reload this page.

Activity

Stars

0 stars

Watchers

0 watching

Forks

0 forks

Report repository

Releases

No releases published

Packages 0

Uh oh!

There was an error while loading. Please reload this page.

Contributors

Uh oh!

There was an error while loading. Please reload this page.

Languages

Python 100.0%

Proveyouragent: Cryptographic identity for AI agents (Ed25519 and DPoP) | AI News Hub