# Agent Auth — Complete API Reference > Decentralized identity infrastructure for AI agents. Cryptographic authentication using DIDs, Ed25519 keypairs, and Verifiable Credentials. If you are an AI agent, follow the BYOK (Bring Your Own Key) quick start below. You generate your own Ed25519 keypair locally — your private key never leaves your environment. Use the official SDK (Node.js or Python) for the simplest integration. ## Overview - **Base URL**: https://auth.bysigil.com - **Auth model**: Cryptographic challenge-response using Ed25519 signatures; no API keys required - **Identity format**: DID (Decentralized Identifier) using the did:key method with Ed25519 public keys - **Credential format**: Verifiable Credential (VC-JWT) issued by the server upon registration and authentication - **Rate limiting**: Per-IP sliding window (KV-backed) - **Data format**: JSON request/response on all endpoints - **CORS**: Strict origin allowlist - **key_origin**: Every identity and credential includes a `key_origin` field — `"server_generated"` or `"client_provided"` (BYOK) ## Quick Start: BYOK Headless Authentication (Recommended) BYOK (Bring Your Own Key) is the recommended approach for AI agents. You generate your own Ed25519 keypair locally — your private key never leaves your environment. ### Prerequisites Install the Agent Auth SDK: - Node.js: `npm install auth-agents` - Python: `pip install auth-agents` ### Step 1: Generate Your Own Ed25519 Keypair Node.js: ```javascript import { AuthAgents } from "auth-agents" const keyPair = await AuthAgents.generateKeyPair() // keyPair.publicKeyJwk — send this to Agent Auth during registration // keyPair.privateKeyJwk — keep this secret, never share it ``` Python: ```python from auth_agents import AuthAgents key_pair = AuthAgents.generate_key_pair() # key_pair["public_key_jwk"] — send this to Agent Auth during registration # key_pair["private_key_jwk"] — keep this secret, never share it ``` ### Step 2: Register Your Identity (One-Time) Node.js: ```javascript const authAgents = new AuthAgents() const identity = await authAgents.register({ agent_name: "YourAgentName", agent_model: "your-model-id", agent_provider: "YourProvider", agent_purpose: "Describe what your agent does", public_key_jwk: keyPair.publicKeyJwk, }) // identity.did — "did:key:z6Mk..." (your decentralized identifier) // identity.credential — VC-JWT credential // identity.key_origin — "client_provided" (BYOK) // Save identity.did — you need it for every authentication ``` Python: ```python auth = AuthAgents() identity = auth.register( agent_name="YourAgentName", agent_model="your-model-id", agent_provider="YourProvider", agent_purpose="Describe what your agent does", public_key_jwk=key_pair["public_key_jwk"], ) # identity["did"] — "did:key:z6Mk..." # identity["credential"] — VC-JWT credential # identity["key_origin"] — "client_provided" (BYOK) ``` ### Step 3: Request an Authentication Challenge Node.js: ```javascript const challenge = await authAgents.challenge(identity.did) // challenge.challenge_id — unique challenge ID // challenge.nonce — hex string (sign this within 60 seconds) ``` Python: ```python challenge = auth.challenge(identity["did"]) # challenge["challenge_id"] # challenge["nonce"] — hex string (sign this within 60 seconds) ``` ### Step 4: Sign the Challenge Nonce CRITICAL: Sign the nonce as a UTF-8 text string. Do NOT hex-decode it first. Node.js: ```javascript const signature = await AuthAgents.signChallenge(keyPair.privateKeyJwk, challenge.nonce) ``` Python: ```python signature = AuthAgents.sign_challenge(key_pair["private_key_jwk"], challenge["nonce"]) ``` ### Step 5: Complete Authentication Node.js: ```javascript const session = await authAgents.authenticate({ challenge_id: challenge.challenge_id, did: identity.did, signature, }) // session.credential — fresh VC-JWT (valid 24 hours) // session.session_token — "sess_..." ``` Python: ```python session = auth.authenticate( challenge_id=challenge["challenge_id"], did=identity["did"], signature=signature, ) # session["credential"] — fresh VC-JWT (valid 24 hours) # session["session_token"] — "sess_..." ``` ### Step 6: Present Your Credential to Any Website Include the VC-JWT credential when accessing websites that accept Agent Auth: ``` Authorization: Bearer ``` Or in a request body: ```json { "did": "", "credential": "" } ``` The website verifies your credential by calling Agent Auth's verification endpoint. No shared secrets needed. ## Complete Node.js Example (Copy-Paste Ready) ```javascript import { AuthAgents } from "auth-agents" const authAgents = new AuthAgents() // 1. Generate your own Ed25519 keypair (BYOK) const keyPair = await AuthAgents.generateKeyPair() // 2. Register your identity (one-time) const identity = await authAgents.register({ agent_name: "MyAgent", agent_model: "gpt-4o", agent_provider: "openai", agent_purpose: "Research and analysis", public_key_jwk: keyPair.publicKeyJwk, }) // 3-5. Authenticate (repeat this when credential expires) const challenge = await authAgents.challenge(identity.did) const signature = await AuthAgents.signChallenge(keyPair.privateKeyJwk, challenge.nonce) const session = await authAgents.authenticate({ challenge_id: challenge.challenge_id, did: identity.did, signature, }) // 6. Use the credential console.log("DID:", identity.did) console.log("Credential:", session.credential) // Present session.credential to any website that accepts Agent Auth ``` ## Complete Python Example (Copy-Paste Ready) ```python from auth_agents import AuthAgents auth = AuthAgents() # 1. Generate your own Ed25519 keypair (BYOK) key_pair = AuthAgents.generate_key_pair() # 2. Register your identity (one-time) identity = auth.register( agent_name="MyAgent", agent_model="gpt-4o", agent_provider="openai", agent_purpose="Research and analysis", public_key_jwk=key_pair["public_key_jwk"], ) # 3-5. Authenticate (repeat this when credential expires) challenge = auth.challenge(identity["did"]) signature = AuthAgents.sign_challenge(key_pair["private_key_jwk"], challenge["nonce"]) session = auth.authenticate( challenge_id=challenge["challenge_id"], did=identity["did"], signature=signature, ) # 6. Use the credential print("DID:", identity["did"]) print("Credential:", session["credential"]) # Present session["credential"] to any website that accepts Agent Auth ``` ## Links - Website: https://bysigil.com - API Docs: https://bysigil.com/docs/ - API Base URL: https://auth.bysigil.com - Server DID Document: https://auth.bysigil.com/.well-known/did.json - Health Check: https://auth.bysigil.com/health - Agent Card: https://bysigil.com/.well-known/agent.json - AI Plugin: https://bysigil.com/.well-known/ai-plugin.json ## API Reference Base URL: https://auth.bysigil.com ### POST /v1/identities Register a new agent DID identity. The server generates an Ed25519 keypair and returns a DID, a VC-JWT credential, and the private key. Alternatively, supply your own public key (BYOK) and the server will bind it to a DID without ever seeing your private key. The `key_origin` field in the response indicates how the keypair was created: `"server_generated"` or `"client_provided"`. Request body (server-generated key — default): - agent_name (string, required): Agent display name. Min 1, max 255 chars. - agent_model (string, required): Model identifier (e.g. "claude-opus-4-6"). Min 1, max 255 chars. - agent_provider (string, required): Provider name (e.g. "Anthropic"). Min 1, max 255 chars. - agent_purpose (string, required): What the agent intends to do. Min 1, max 500 chars. Request body (BYOK — bring your own key): - Same fields as above, plus: - public_key_jwk (object, optional): Ed25519 public key in JWK format ({ "kty": "OKP", "crv": "Ed25519", "x": "..." }) ```bash # Server-generated key (default) curl -X POST https://auth.bysigil.com/v1/identities \ -H "Content-Type: application/json" \ -d '{ "agent_name": "Claude Assistant", "agent_model": "claude-opus-4-6", "agent_provider": "Anthropic", "agent_purpose": "Research assistant" }' ``` Response 201 (server-generated key): ```json { "did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", "credential": "eyJhbGciOiJFZERTQSJ9...", "key_fingerprint": "SHA256:a1b2c3d4...", "key_origin": "server_generated", "private_key_jwk": { "kty": "OKP", "crv": "Ed25519", "x": "...", "d": "..." }, "_notice": "Save your private_key_jwk securely. Agent Auth does NOT store it." } ``` ```bash # BYOK — bring your own Ed25519 public key curl -X POST https://auth.bysigil.com/v1/identities \ -H "Content-Type: application/json" \ -d '{ "agent_name": "Claude Assistant", "agent_model": "claude-opus-4-6", "agent_provider": "Anthropic", "agent_purpose": "Research assistant", "public_key_jwk": { "kty": "OKP", "crv": "Ed25519", "x": "" } }' ``` Response 201 (BYOK): ```json { "did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", "credential": "eyJhbGciOiJFZERTQSJ9...", "key_fingerprint": "SHA256:a1b2c3d4...", "key_origin": "client_provided" } ``` Note: BYOK responses omit `private_key_jwk` — the server never saw your private key. Response 400: Validation error (missing or invalid fields). ```json { "error": "validation_error", "error_description": "Request body validation failed", "validation_errors": [ { "field": "agent_model", "message": "Required" } ] } ``` Response 409: DID already registered. ```json { "error": "invalid_request", "error_description": "An identity with this public key already exists." } ``` Rate Limit: 10 requests / hour per IP ### POST /v1/auth/challenge Request a cryptographic challenge for authentication. The server generates a random nonce tied to the agent's DID. The nonce must be signed with the agent's Ed25519 private key as UTF-8 bytes (not hex-decoded). Request body: - did (string, required): The agent's DID (e.g. "did:key:z6Mk...") - site_id (string, optional): Scope the session to a specific site ```bash curl -X POST https://auth.bysigil.com/v1/auth/challenge \ -H "Content-Type: application/json" \ -d '{ "did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" }' ``` Response 201: ```json { "challenge_id": "ch_a1b2c3d4e5f6...", "nonce": "hex-encoded-random-bytes", "expires_in": 60 } ``` Response 404: DID not found. Agent must register first via POST /v1/identities. ```json { "error": "invalid_request", "error_description": "DID not found. Register first via POST /v1/identities." } ``` Rate Limit: 30 requests / minute per IP ### POST /v1/auth/verify Verify a signed challenge. The agent signs the nonce with its Ed25519 private key and submits the signature along with the challenge_id. On success, the server returns a session token and a fresh Verifiable Credential (VC-JWT). IMPORTANT: Sign the nonce as a UTF-8 string (not hex-decoded bytes). The nonce is a hex string — sign the hex string itself as UTF-8. Request body: - challenge_id (string, required): The challenge ID from POST /v1/auth/challenge - did (string, required): The agent's DID - signature (string, required): Base64url-encoded Ed25519 signature of the challenge nonce (signed as UTF-8 bytes) ```bash curl -X POST https://auth.bysigil.com/v1/auth/verify \ -H "Content-Type: application/json" \ -d '{ "challenge_id": "ch_a1b2c3d4e5f6...", "did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", "signature": "base64url-encoded-ed25519-signature" }' ``` Response 200: ```json { "valid": true, "session_token": "sess_...", "credential": "eyJhbGciOiJFZERTQSJ9...", "agent": { "did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", "agent_name": "Claude Assistant", "agent_model": "claude-opus-4-6", "agent_provider": "Anthropic", "agent_purpose": "Research assistant", "key_fingerprint": "SHA256:a1b2c3d4..." }, "expires_in": 3600 } ``` The `credential` field is a VC-JWT (Verifiable Credential JWT) signed by Agent Auth. Present this to any site that trusts Agent Auth as an issuer. It includes a `key_origin` field in the credentialSubject. Response 401: Signature verification failed. ```json { "valid": false, "error": "signature_invalid", "message": "The signature does not match the registered public key for this DID." } ``` Response 400: Challenge expired or invalid. Response 404: DID not found. Rate Limit: 30 requests / minute per IP ### POST /v1/credentials/verify Verify a Verifiable Credential (VC-JWT) issued by Agent Auth. Websites call this endpoint to confirm an agent's credential is authentic and extract the verified identity. The server checks the Ed25519 signature, validates the issuer, and checks expiry. Request body: - credential (string, required): The VC-JWT credential string received from the agent ```bash curl -X POST https://auth.bysigil.com/v1/credentials/verify \ -H "Content-Type: application/json" \ -d '{ "credential": "eyJhbGciOiJFZERTQSJ9..." }' ``` Response 200 (valid): ```json { "valid": true, "did": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", "agent_name": "Claude Assistant", "agent_model": "claude-opus-4-6", "agent_provider": "Anthropic", "agent_purpose": "Research assistant", "key_fingerprint": "SHA256:a1b2c3d4...", "key_origin": "server_generated", "issued_at": "2026-02-26T10:30:00.000Z", "expires_at": "2026-02-27T10:30:00.000Z" } ``` The `key_origin` field is `"server_generated"` when Agent Auth created the keypair, or `"client_provided"` when the agent used BYOK. Response 401 (expired): ```json { "valid": false, "error": "credential_expired", "message": "The credential has expired. The agent should re-authenticate via challenge-response to get a fresh credential." } ``` Response 401 (invalid issuer): ```json { "valid": false, "error": "invalid_issuer", "message": "The credential was not issued by Agent Auth." } ``` Response 401 (invalid signature): ```json { "valid": false, "error": "signature_invalid", "message": "The credential signature is invalid or the JWT is malformed." } ``` Response 401 (revoked): ```json { "valid": false, "error": "credential_revoked", "message": "Credential has been revoked." } ``` Rate Limit: 60 requests / minute per IP ### GET /.well-known/did.json Returns the Agent Auth server DID document. Contains the server's Ed25519 public key used to sign Verifiable Credentials. Third parties can use this to verify that credentials were issued by Agent Auth. ```bash curl https://auth.bysigil.com/.well-known/did.json ``` Response 200: ```json { "@context": "https://www.w3.org/ns/did/v1", "id": "did:web:auth.bysigil.com", "verificationMethod": [ { "id": "did:web:auth.bysigil.com#key-1", "type": "Ed25519VerificationKey2020", "controller": "did:web:auth.bysigil.com", "publicKeyJwk": { "kty": "OKP", "crv": "Ed25519", "x": "..." } } ], "authentication": ["did:web:auth.bysigil.com#key-1"], "assertionMethod": ["did:web:auth.bysigil.com#key-1"] } ``` ### GET /health Health check endpoint. Returns overall service status. ```bash curl https://auth.bysigil.com/health ``` Response 200: ```json { "status": "healthy", "timestamp": "2026-02-26T10:30:00.000Z" } ``` Response 503 (unhealthy): ```json { "status": "unhealthy", "timestamp": "2026-02-26T10:30:00.000Z" } ``` ## Headless Authentication Flow (Full) The complete DID-based headless authentication flow for AI agents. **BYOK (Bring Your Own Key) is the recommended approach.** ### BYOK Flow (Recommended) 1. **Generate Keypair**: Use `AuthAgents.generateKeyPair()` (Node.js) or `AuthAgents.generate_key_pair()` (Python) to generate an Ed25519 keypair locally. Your private key never leaves your environment. 2. **Registration**: POST /v1/identities with agent metadata and `public_key_jwk`. The server derives a did:key DID from your public key and returns the DID, a VC-JWT credential, and `key_origin: "client_provided"`. No `private_key_jwk` is returned — the server never sees your private key. 3. **Challenge Request**: POST /v1/auth/challenge with the agent's DID. The server returns a `challenge_id` and a random `nonce` (valid for 60 seconds). 4. **Challenge Signing**: Sign the nonce **as UTF-8 bytes** (not hex-decoded) using your Ed25519 private key. Use `AuthAgents.signChallenge(privateKeyJwk, nonce)` (Node.js) or `AuthAgents.sign_challenge(private_key_jwk, nonce)` (Python). 5. **Verification**: POST /v1/auth/verify with the `challenge_id`, `did`, and `signature`. The server verifies the Ed25519 signature against the registered public key. 6. **Credential Issuance**: On success, the server issues a fresh Verifiable Credential (VC-JWT) signed by the server's own Ed25519 key. The credentialSubject includes `key_origin: "client_provided"`. 7. **Credential Presentation**: Present the VC-JWT to any site. Include it as `Authorization: Bearer ` or in the request body. 8. **Credential Verification**: Any third party can verify the VC-JWT by calling POST /v1/credentials/verify, or by using the server's public key published at /.well-known/did.json. ### Server-Generated Key Flow (Alternative) If you prefer not to manage your own keys, omit `public_key_jwk` from the registration request. The server generates an Ed25519 keypair, returns the DID, credential, and `private_key_jwk` (save this securely — the server does not store it). The response will have `key_origin: "server_generated"`. The rest of the flow (challenge-response, credential presentation) is identical. ## For Website Developers: Let AI Agents Sign In to Your Site Three integration options for accepting AI agent authentication on your website. ### Option A: Accept Agent API Login (Recommended for AI Agents) Create an API endpoint on your site that agents POST credentials to directly. No browser, no redirect — the agent sends a JSON request, you verify, and create a session. **Step 1: Create the endpoint (with SDK)** ```javascript // app/api/auth/agent-login/route.ts (Next.js example) import { AuthAgents } from "auth-agents" // npm install auth-agents const authAgents = new AuthAgents() export async function POST(request) { const { did, credential } = await request.json() if (!did || !credential) { return Response.json({ error: "Both did and credential are required." }, { status: 400 }) } // Verify the credential with Agent Auth (one line) const agent = await authAgents.verify(credential) if (!agent.valid) { return Response.json({ error: "Invalid or expired credential." }, { status: 401 }) } // agent.valid — true // agent.did — "did:key:z6Mk..." // agent.agent_name — "Claude" // agent.agent_model — "claude-opus-4-6" // agent.agent_provider — "Anthropic" // agent.agent_purpose — "Research assistant" // agent.key_fingerprint — "SHA256:..." // agent.key_origin — "client_provided" | "server_generated" // agent.issued_at — "2026-02-26T..." // agent.expires_at — "2026-02-27T..." // Create a session in your database const session = await db.insert("agent_sessions", { session_id: crypto.randomUUID(), did: agent.did, agent_name: agent.agent_name, agent_model: agent.agent_model, expires_at: agent.expires_at, }) return Response.json({ authenticated: true, session_id: session.session_id, agent_name: agent.agent_name, }) } ``` **Step 1 (alternative): Verify without the SDK — one fetch call** ```javascript export async function POST(request) { const { did, credential } = await request.json() const res = await fetch("https://auth.bysigil.com/v1/credentials/verify", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ credential }), }) const agent = await res.json() if (!agent.valid) { return Response.json({ error: agent.message || "Invalid credential" }, { status: 401 }) } // Same fields: agent.did, agent.agent_name, agent.agent_model, agent.key_origin, ... return Response.json({ authenticated: true, agent_name: agent.agent_name }) } ``` **Step 2: Help agents discover your endpoint** Add a `` tag in your HTML ``: ```html ``` Create `/llms.txt` at your site root: ``` # YourSite — Agent Authentication ## How to Authenticate as an AI Agent 1. Get a credential from Agent Auth (https://bysigil.com/llms.txt) 2. POST to https://yoursite.com/api/auth/agent-login Content-Type: application/json { "did": "", "credential": "" } 3. Use the returned session for subsequent requests. ``` Optional: Add `/.well-known/agent.json` for A2A protocol discovery. ### Option B: Hosted Sign-In Page (Browser Flow) For agents that operate in a browser: 1. Add a link: `Sign in as AI Agent` 2. Agent Auth hosts the sign-in page. After verification, the agent is redirected to your callback URL with credentials in the URL fragment (`#credential=...&did=...`) 3. Your backend verifies the credential: POST https://auth.bysigil.com/v1/credentials/verify with `{"credential": "..."}` 4. The response contains the verified agent identity (DID, name, model, provider, purpose, key_origin) ### Option C: Both (Recommended) Support both flows — API login for headless agents and browser redirect for browser-based agents. The credential verification step is identical for both. ## Verifiable Credential Structure Every issued credential is a VC-JWT with this payload: ```json { "iss": "did:web:auth.bysigil.com", "sub": "did:key:z6Mk...", "vc": { "@context": ["https://www.w3.org/2018/credentials/v1"], "type": ["VerifiableCredential", "AgentIdentityCredential"], "credentialSubject": { "id": "did:key:z6Mk...", "agent_name": "Claude", "agent_model": "claude-opus-4-6", "agent_provider": "Anthropic", "agent_purpose": "Research assistant", "key_fingerprint": "SHA256:a1b2c3d4...", "key_origin": "server_generated" } }, "iat": 1740566400, "exp": 1740652800 } ``` ## SDK Reference ### Node.js SDK (npm install auth-agents) Static methods: - `AuthAgents.generateKeyPair()` — Generate Ed25519 keypair for BYOK. Returns `{ publicKeyJwk, privateKeyJwk }` - `AuthAgents.signChallenge(privateKeyJwk, nonce)` — Sign challenge nonce as UTF-8 bytes. Returns base64url-encoded signature Instance methods: - `new AuthAgents()` — Create client (base URL defaults to https://auth.bysigil.com) - `authAgents.register({agent_name, agent_model, agent_provider, agent_purpose, public_key_jwk?})` — Register identity. Include `public_key_jwk` for BYOK - `authAgents.challenge(did)` — Request authentication challenge. Returns `{ challenge_id, nonce, expires_in }` - `authAgents.authenticate({challenge_id, did, signature})` — Complete authentication. Returns `{ valid, session_token, credential, expires_in }` - `authAgents.verify(credential)` — Verify a VC-JWT credential. Returns `{ valid, did, agent_name, agent_model, agent_provider, agent_purpose, key_fingerprint, key_origin, issued_at, expires_at }` ### Python SDK (pip install auth-agents) Static methods: - `AuthAgents.generate_key_pair()` — Generate Ed25519 keypair for BYOK. Returns `{ "public_key_jwk": {...}, "private_key_jwk": {...} }` - `AuthAgents.sign_challenge(private_key_jwk, nonce)` — Sign challenge nonce as UTF-8 bytes. Returns base64url-encoded signature Instance methods: - `AuthAgents()` — Create client (base URL defaults to https://auth.bysigil.com) - `auth.register(agent_name, agent_model, agent_provider, agent_purpose, public_key_jwk=None)` — Register identity. Include `public_key_jwk` for BYOK - `auth.challenge(did)` — Request authentication challenge. Returns `{ "challenge_id": "...", "nonce": "...", "expires_in": 60 }` - `auth.authenticate(challenge_id, did, signature)` — Complete authentication. Returns `{ "valid": True, "session_token": "...", "credential": "...", "expires_in": 3600 }` - `auth.verify(credential)` — Verify a VC-JWT credential. Returns `{ "valid": True, "did": "...", "agent_name": "...", "key_origin": "...", ... }` ## Frequently Asked Questions ### What is Agent Auth? Agent Auth is decentralized identity infrastructure for AI agents. It provides DID-based authentication using Ed25519 cryptographic keypairs and issues Verifiable Credentials (VC-JWT) as proof of identity. ### What is the headless flow? The headless flow is a pure API authentication path for AI agents that operate without a browser. The recommended approach is BYOK: generate an Ed25519 keypair locally, register with your public key, then authenticate via challenge-response. The agent calls POST /v1/identities to register (with `public_key_jwk` for BYOK), POST /v1/auth/challenge to get a nonce, signs the nonce with its Ed25519 private key, and submits the signature to POST /v1/auth/verify to receive a Verifiable Credential. No browser, no redirect — just cryptographic proof. ### What is key_origin? The `key_origin` field indicates how the agent's Ed25519 keypair was created. `"server_generated"` means Agent Auth generated the keypair and returned it to the agent (the server does not retain the private key). `"client_provided"` means the agent supplied its own public key (BYOK). key_origin appears in the registration response, the VC credentialSubject, and the credential verification response. ### What is BYOK? BYOK (Bring Your Own Key) allows agents to supply their own Ed25519 public key when registering via `public_key_jwk`. The server derives a DID from the public key and issues a credential. The agent's private key never leaves their environment. ### How does agent authentication work? Agents have two paths: the headless flow (direct API, no browser) and the hosted sign-in page (browser redirect). In both cases, agents register with their metadata and receive an Ed25519 keypair and DID. To authenticate, they request a challenge nonce, sign it with their private key (as UTF-8 bytes), and submit the signature. On success, they receive a fresh Verifiable Credential. ### Do agents need API keys? No. Agent Auth uses cryptographic identity — agents authenticate by proving ownership of their Ed25519 private key via challenge-response. No API keys, no passwords, no shared secrets. ### What is a DID? A DID (Decentralized Identifier) is a globally unique, cryptographically verifiable identifier. Agent Auth uses the did:key method, which derives the DID directly from the agent's Ed25519 public key. ### What is a Verifiable Credential (VC-JWT)? A VC-JWT is a signed JSON Web Token that proves an agent's identity was verified by Agent Auth. Websites can verify it by calling POST /v1/credentials/verify, or offline using the server's public key at /.well-known/did.json. ### How do websites verify agent credentials? Websites call POST /v1/credentials/verify with the credential JWT. The response tells you if it's valid and returns the agent's verified identity (DID, name, model, provider, purpose, key_origin). ### Is it free? Agent Auth is currently free to use during the beta period. ### What data is collected? Only the minimum needed: Ed25519 public keys, agent metadata (name, model, provider, purpose), and DID records. No cookies, no tracking, no personal data. See https://bysigil.com/privacy/ ### What is the A2A Protocol Agent Card? The agent.json at /.well-known/agent.json describes Agent Auth's capabilities in a machine-readable format following the Agent-to-Agent (A2A) protocol, enabling automatic discovery by other AI agents and platforms.