View on GitHub →
← Back to Home

Agent Identity with Rust

An interactive guide to AgentPin — generate keys, issue credentials, and verify agent identity.

The Problem: AI Agent Impersonation

As AI agents become more autonomous and interact with external services, a critical question arises: how do you know which agent you're talking to?

Without cryptographic identity, any agent can claim to be any other agent. A malicious actor could deploy an agent that impersonates a trusted service, exfiltrating data or performing unauthorized actions.

AgentPin solves this with domain-anchored cryptographic credentials — ES256 JWTs tied to discoverable public keys, with capability scoping, delegation chains, and TOFU key pinning.

Step 1: Install the CLI

Install the AgentPin CLI tools via Cargo.

cargo install agentpin

Step 2: Generate Keys

Generate an ECDSA P-256 keypair anchored to your domain.

agentpin keygen \
  --domain example.com \
  --kid my-key-01 \
  --output-dir ./keys

This creates PEM and JWK files in the output directory:

ls ./keys/
# my-key-01.private.pem
# my-key-01.public.pem
# my-key-01.private.jwk
# my-key-01.public.jwk

Step 3: Create Discovery Document

Create a discovery document that declares your agent's identity and capabilities. This will be served at .well-known/agent-identity.json.

{
  "agentpin_version": "0.1",
  "entity": "example.com",
  "entity_type": "maker",
  "public_keys": [
    {
      "kid": "my-key-01",
      "kty": "EC",
      "crv": "P-256",
      "x": "<base64url-encoded-x>",
      "y": "<base64url-encoded-y>",
      "use": "sig"
    }
  ],
  "agents": [
    {
      "agent_id": "urn:agentpin:example.com:my-agent",
      "name": "My Agent",
      "capabilities": ["read:data", "write:reports"],
      "status": "active"
    }
  ],
  "max_delegation_depth": 2,
  "updated_at": "2026-02-08T00:00:00Z"
}

Save this as discovery.json. Use the JWK x and y values from your generated public key.

Step 4: Issue a Credential

Issue a signed JWT credential for your agent.

agentpin issue \
  --private-key ./keys/my-key-01.private.pem \
  --kid my-key-01 \
  --issuer example.com \
  --agent-id urn:agentpin:example.com:my-agent \
  --capabilities read:data,write:reports \
  --ttl 3600

This outputs a compact ES256 JWT:

eyJ0eXAiOiJhZ2VudHBpbi1jcmVkZW50aWFsK2p3dCIsImFsZyI6IkVTMjU2Iiwia2lkIjoibXkta2V5LTAxIn0.eyJpc3MiOiJleGFtcGxlLmNvbSIsInN1YiI6InVybjphZ2VudHBpbjpleGFtcGxlLmNvbTpteS1hZ2VudCIsImlhdCI6MTczODk3MjgwMCwiZXhwIjoxNzM4OTc2NDAwLCJqdGkiOiI1NTBiOTYzMy1lMjRiLTRlMzEtODk3ZC0xYWYzMDA3YzI5YzAiLCJhZ2VudHBpbl92ZXJzaW9uIjoiMC4xIiwiY2FwYWJpbGl0aWVzIjpbInJlYWQ6ZGF0YSIsIndyaXRlOnJlcG9ydHMiXX0.MEUCIQDhZ...

Step 5: Verify a Credential

Verify a credential against the discovery document.

agentpin verify \
  --credential ./credential.jwt \
  --discovery ./discovery.json \
  --offline

Verification Result

Valid Credential Expired / Revoked
VERIFIED
  Agent:        urn:agentpin:example.com:my-agent
  Issuer:       example.com
  Capabilities: read:data, write:reports
  Key Pinning:  first_use (pinned)
  Expires:      2026-02-08T01:00:00Z

Step 6: Serve Discovery Endpoints

Run the AgentPin server to host your discovery and revocation documents.

agentpin-server \
  --discovery ./discovery.json \
  --port 8080

This serves the following endpoints:

GET /.well-known/agent-identity.json          → Discovery document
GET /.well-known/agent-identity-revocations.json → Revocation list
GET /health                                    → Health check

Optionally include a revocation document:

agentpin-server \
  --discovery ./discovery.json \
  --revocation ./revocations.json \
  --bind 0.0.0.0 \
  --port 8080