Domain-anchored cryptographic identity for AI agents. The second layer in the ThirdKey trust stack (SchemaPin → AgentPin → Symbiont).
AgentPin lets organizations publish verifiable identity documents for their AI agents, issue short-lived cryptographic credentials (JWTs), and verify agent identity using a 12-step protocol with TOFU key pinning, capability validation, delegation chains, and revocation checking.
- Discovery — Organizations publish
/.well-known/agent-identity.jsondeclaring their agents, public keys, and capabilities - Credentials — ES256 (ECDSA P-256) signed JWTs with agent identity, capabilities, constraints, and optional delegation chains
- Verification — 12-step flow: JWT parsing, temporal validation, discovery resolution, signature verification, revocation checking, agent status, capability/constraint validation, delegation chain verification, TOFU key pinning, and audience matching
- Mutual Authentication — Challenge-response protocol with 128-bit nonces for bidirectional identity verification
- Revocation — Credential, agent, and key-level revocation via
/.well-known/agent-identity-revocations.json
See AGENTPIN_TECHNICAL_SPECIFICATION.md for the full protocol spec (v0.1.0-draft).
crates/
├── agentpin/ # Core Rust library (publishable to crates.io)
├── agentpin-cli/ # CLI binary
└── agentpin-server/ # HTTP server for discovery/revocation endpoints
javascript/ # JavaScript/Node.js package (zero dependencies)
python/ # Python package (uses cryptography library)
All three implementations share the same API surface and produce interoperable credentials — a JWT issued by one language can be verified by any other.
agentpin keygen --domain example.com --kid example-2026-01 --output-dir ./keysGenerates example-2026-01.private.pem, example-2026-01.public.pem, and example-2026-01.public.jwk.json.
agentpin issue \
--private-key ./keys/example-2026-01.private.pem \
--kid example-2026-01 \
--issuer example.com \
--agent-id "urn:agentpin:example.com:scout" \
--capabilities "read:data,write:reports" \
--ttl 3600Outputs a signed JWT to stdout.
Offline (with local discovery document):
agentpin verify \
--credential <jwt> \
--discovery ./agent-identity.json \
--pin-store ./pins.jsonOnline (fetches discovery from issuer domain):
agentpin verify --credential <jwt>Outputs a JSON verification result with validity, capabilities, key pinning status, and any errors.
agentpin-server \
--discovery ./agent-identity.json \
--revocation ./revocations.json \
--port 8080Serves:
GET /.well-known/agent-identity.json(Cache-Control: max-age=3600)GET /.well-known/agent-identity-revocations.json(Cache-Control: max-age=300)GET /health
cargo build --workspace
cargo test --workspaceThe core library has no mandatory HTTP dependency. Network fetching is behind the fetch feature flag:
[dependencies]
agentpin = { version = "0.1", features = ["fetch"] }Requires Node.js >= 18. Zero external dependencies — uses Node.js built-in crypto.
cd javascript
npm install # dev dependencies only (eslint, c8)
npm test # runs all 76 testsimport { generateKeyPair, pemToJwk, issueCredential, Capability,
verifyCredentialOffline, KeyPinStore, buildDiscoveryDocument } from 'agentpin';
const { privateKey, publicKey } = generateKeyPair();
const jwk = pemToJwk(publicKey, 'my-key-2026');
const credential = issueCredential(
privateKey, 'my-key-2026', 'example.com',
'urn:agentpin:example.com:agent', 'verifier.com',
[new Capability('read:data')], null, null, 3600
);
const result = verifyCredentialOffline(
credential, discovery, null, new KeyPinStore(), 'verifier.com'
);Requires Python >= 3.8.
cd python
pip install -e ".[dev]"
pytest tests/ -v # runs all 76 testsfrom agentpin import (
generate_key_pair, pem_to_jwk, issue_credential,
verify_credential_offline, KeyPinStore, Capability,
build_discovery_document, EntityType, AgentStatus,
)
private_key, public_key = generate_key_pair()
jwk = pem_to_jwk(public_key, "my-key-2026")
credential = issue_credential(
private_key, "my-key-2026", "example.com",
"urn:agentpin:example.com:agent", "verifier.com",
[Capability("read:data")], None, None, 3600,
)
result = verify_credential_offline(
credential, discovery, None, KeyPinStore(), "verifier.com"
)- ES256 only — Rejects all other JWT algorithms to prevent algorithm confusion attacks
- Inline JWT implementation — No external JWT library in any language; we control algorithm validation
- No-redirect enforcement — HTTP client configured to reject redirects per spec security requirements
- Feature-gated HTTP — Core libraries work offline; network fetching is opt-in
- TOFU key pinning — Trust-on-first-use with JWK thumbprint (RFC 7638) for key continuity verification
- Cross-language interop — All three implementations use DER-encoded ECDSA signatures and identical JSON field names, so credentials are fully interoperable
MIT - Jascha Wanger / ThirdKey.ai