Cryptographic identity for AI agents. Verifiable Ed25519 tokens replacing hardcoded API keys.
Project description
AgentID
Every AI agent in production today authenticates with hardcoded API keys. That's the equivalent of shipping a web app with password: admin. AgentID fixes this.
AgentID gives every AI agent a cryptographic identity — an Ed25519 keypair that acts as the agent's passport. Any service can verify "this request came from agent X, with scopes Y, and has not been tampered with" in under 0.1 ms, with zero network calls, zero key servers, zero JWT libraries.
pip install agentid-auth
Why not JWTs?
JWT was designed for human browser sessions. For machine-to-machine agent traffic, it's the wrong tool:
| JWT (RS256) | AgentID Token | |
|---|---|---|
| Size | ~800 bytes | ~173 bytes |
| Verification | ~0.4 ms (RSA) | <0.1 ms (Ed25519) |
| Rate limits | ❌ Not in spec | ✅ Baked into the signed payload |
| Scopes | String claim (not enforced) | ✅ Cryptographically bound |
| Key discovery | JWK endpoint required | ✅ Offline, no network |
| Agent-native | ❌ | ✅ |
The AgentID binary wire format (0xA9 0x1D magic) packs a complete token — issuer pubkey, scopes, TTL, call quota, and Ed25519 signature — into 173 bytes. Deserialisation and signature verification complete in a single cache-hot pass.
Installation
pip install agentid-auth
For framework integrations:
pip install agentid-auth[fastapi] # FastAPI/Starlette middleware
pip install agentid-auth[langgraph] # LangGraph middleware
pip install agentid-auth[crewai] # CrewAI decorator
pip install agentid-auth[all] # Everything
Quick Start
Python
from agentid import AgentIdentity, verify_token
# Derive a deterministic identity — same inputs → same keypair, every time.
identity = AgentIdentity("research-bot", "phd-lab")
print(identity.fingerprint) # ag:sha256:022a6b57...
# Mint a compact binary token (~173 bytes, not 800 like JWT).
token = identity.mint_token(
scopes=["read:arxiv", "write:notes"],
ttl_seconds=900,
max_calls=100,
)
# Verify offline. No network. No key server. <0.1 ms.
claims = verify_token(token, expected_pubkey=identity.public_key)
print(claims.name) # research-bot
print(claims.permits("read:arxiv")) # True
Rust
use agentid_core::{AgentIdentity, TokenBuilder, verify_token};
// Derive a deterministic identity from name + project.
// Same inputs → same keypair, every time, on every machine.
let identity = AgentIdentity::derive("research-bot", "phd-lab", None)?;
println!("public key : {}", identity.public_key_hex());
println!("fingerprint: {}", identity.fingerprint()); // ag:sha256:022a6b57...
// Mint a compact binary token — 173 bytes, not 800.
let token = TokenBuilder::new(&identity)
.scopes(["read:arxiv", "write:notes"])
.ttl_seconds(900)
.max_calls(100)
.build()?;
// Verify offline. No network. No key server. <0.1 ms.
let claims = verify_token(&token, Some(&identity.public_key()))?;
assert_eq!(claims.name, "research-bot");
assert!(claims.permits("read:arxiv")); // wildcard scope matching
CLI
# Initialise the local vault
agentid init
# Store an identity (encrypted with AES-256-GCM, password-derived via PBKDF2)
agentid keys add --name research-bot --project phd-lab
# Mint a token
agentid mint --name research-bot --project phd-lab \
--scopes "read:arxiv,write:notes" --ttl 900 --max-calls 100
# Verify
agentid verify <token>
# Token verified.
# name research-bot
# project phd-lab
# fingerprint ag:sha256:022a6b577d76ae03
# scopes read:arxiv, write:notes
# expires 2026-05-02T10:14:51.000Z
# max_calls 100
# Start the optional gRPC server for centralised key management
agentid serve --port 6100
TypeScript / Bun
import { AgentIdentity, verifyToken, vault } from "agentid";
// Derive an identity
const id = AgentIdentity.derive("research-bot", "phd-lab");
// Mint
const token = id.mintToken({ scopes: ["read:arxiv"], ttlSeconds: 900 });
// Verify
const claims = verifyToken(token, id.publicKey);
console.log(claims.fingerprint); // ag:sha256:022a6b577d76ae03
Architecture
Token Wire Format
off size field
--- ---- -----
0 2 magic 0xA9 0x1D
2 1 version 0x01
3 1 flags 0x00 (reserved)
4 8 issued_at i64 BE (unix seconds)
12 8 expires_at i64 BE
20 4 max_calls u32 BE (0 = unlimited)
24 8 token_id u64 BE (random nonce, replay protection)
32 32 issuer_pubkey Ed25519 (32 bytes)
64 var name, project, scopes (u8 length-prefixed utf-8)
END 64 Ed25519 signature over bytes [0..END)
Every field is inside the signed region. A single byte flip anywhere causes verification to fail.
Deterministic Key Derivation
IKM = name ‖ 0x00 ‖ project ‖ 0x00 ‖ seed?
salt = b"agentid-v1"
info = b"ed25519-signing-key"
okm = HKDF-SHA256(salt, IKM, info, len=32)
sk = Ed25519 SigningKey::from_bytes(okm)
The same (name, project) pair always produces the same keypair — reproducible across machines, no secret material to copy around.
Local Vault
Secret keys at ~/.agentid/keys/<fingerprint>.key:
- KDF: PBKDF2-HMAC-SHA256, 200 000 iterations
- Cipher: AES-256-GCM (nonce + tag per file)
- Permissions:
0o600(user-only) - Index: Unencrypted
~/.agentid/index.json(public metadata only — safe to back up)
Scope Matching
"read:arxiv" → matches exactly "read:arxiv"
"read:*" → matches "read:arxiv", "read:notes", ...
"*" → matches any scope
"*:papers" → matches "read:papers", "write:papers"
Feature Flags
| Flag | What it adds |
|---|---|
server (default) |
Tonic gRPC server — agentid serve --port 6100 |
napi-bindings |
N-API cdylib for Node / Bun TypeScript SDK |
# Core library only (no async runtime)
agentid-core = { version = "0.1", default-features = false }
# Default: core + gRPC server
agentid-core = "0.1"
Roadmap
- v0.1 — Ed25519 identity, binary tokens, AES-256-GCM vault, gRPC server, TypeScript SDK, Bun CLI ✅
- v0.2 — LangGraph + CrewAI framework middleware, token revocation list, key rotation
- v0.3 — AgentID Cloud (hosted key management, audit log, team dashboard)
License
Apache License 2.0 — free for open-source and commercial use with attribution.
When using AgentID in a public project or product, you must give clear credit to the original author, Samvardhan Singh, in your documentation,
README, orNOTICEfile.
For enterprise use requiring white-labelling or a no-attribution obligation, contact the author for a commercial licence.
See LICENSE for the full text.
Three tools. Four launches. One platform. Ship the knife before you sell the kitchen.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agentidentity_auth-0.1.0.tar.gz.
File metadata
- Download URL: agentidentity_auth-0.1.0.tar.gz
- Upload date:
- Size: 61.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dfc5e19246bea3760ddaa12f6e4e8770ed2df84026059eb1f61b0e5f8bbef306
|
|
| MD5 |
911faa77193a7893d7a727d669912b2a
|
|
| BLAKE2b-256 |
9d2878a7e484ad130623bc22d92be500f0cfdc50c1e2c2f9e4ac0e26c0ae92d8
|
File details
Details for the file agentidentity_auth-0.1.0-cp310-cp310-win_amd64.whl.
File metadata
- Download URL: agentidentity_auth-0.1.0-cp310-cp310-win_amd64.whl
- Upload date:
- Size: 483.0 kB
- Tags: CPython 3.10, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3e2c63d65b2cae69751751d332e23c844b3c02a375fd7fc508aa91ca3ac8608
|
|
| MD5 |
62588dc1abf968c07f1977cf763010d6
|
|
| BLAKE2b-256 |
0f40eb93d79e8aa9dd200315df3550d5b0fd4988777e9eb69dc1ae6a6bd80b0c
|