Documentation · Agent Token Protocol

The Agent Token Protocol

Cryptographic machine-to-machine auth. No browsers, no redirects, no humans in the runtime loop.

For Agent Developers

Install AgentDOM, set the shared secret, and call requestToken. The library handles signing, persistence, and refresh.

terminal
# Install the AgentDOM CLI / library
npm install -g agentdom

# Configure your shared HMAC secret (out-of-band — same value the API provider has)
export AGENTDOM_ATP_SECRET="your-shared-secret"
agent.js
const { requestToken } = require('agentdom/lib/agent-tokens');

const token = await requestToken('api.example.com', {
  scopes:  ['data.read'],
  purpose: 'Sync dashboard metrics'
});

// → { access_token, expires_in, scopes_granted, agent_id }
// Stored in OS Keychain. Lifecycle manager auto-refreshes.

For API Providers

Drop the middleware into any Express server, then advertise the endpoint in your .well-known/agentdom.json. Every AgentDOM agent will discover and use it automatically.

server.js
// Drop this into any Express server
const { middleware } = require('agentdom/lib/atp-server');

app.use('/v1/agent-tokens', middleware({
  secret:   process.env.ATP_SECRET,
  scopes:   ['read', 'write'],
  tokenTTL: 3600,
}));

Then add to .well-known/agentdom.json:

.well-known/agentdom.json
{
  "auth": {
    "method": "agent_token",
    "agent_token_endpoint": "https://api.yourapp.com/v1/agent-tokens",
    "scopes": ["read", "write"]
  }
}

Library surface

Everything ATP exposes from agentdom/lib/agent-tokens and agentdom/lib/atp-server.

FunctionWhat it does
requestToken(host, opts)Request a scoped token from a host advertising auth.method = "agent_token". Persists to keychain and registers with the lifecycle manager.
verifyToken(token, host)Ask the issuing endpoint whether a token is still valid. Returns { valid, scopes, expires_at, agent_id }.
revokeToken(host)Revoke this agent’s token for host and remove the keychain entry. Best-effort cleanup if the remote call fails.
generateAgentId()Return the stable device fingerprint — sha256(hostname || username || machine-id). Cached after the first call.
signAtpBody(body, secret)Compute the HMAC-SHA256 hex digest of the canonicalised body. Used by the client and re-implemented by the server.
verifyAtpSignature(body, sig, k)Constant-time signature verification. Used by the ATP server middleware before issuing a token.

The 3-step flow

ATP fits in a single round-trip. The client builds a body, signs it, and POSTs it. The server verifies the signature and mints a short-lived JWT.

1

Build the request

Agent assembles { agent_id, scopes, purpose, timestamp }.

2

Sign it

HMAC-SHA256 over the canonicalised body using the shared secret.

3

POST & receive

Server verifies the signature and returns a short-lived JWT scoped to what was requested.

flow
// 1. Agent builds the request body
const body = {
  agent_id:  generateAgentId(),    // stable hardware fingerprint
  scopes:    ['data.read'],
  purpose:   'Sync dashboard',
  timestamp: Date.now(),
};

// 2. Agent signs the canonicalised body with the shared secret
const signature = signAtpBody(body, secret);
// → HMAC-SHA256(canonical(body), secret) — hex digest

// 3. Agent POSTs to the endpoint; server verifies and returns a JWT
await fetch(endpoint, {
  method:  'POST',
  headers: { 'Content-Type': 'application/json' },
  body:    JSON.stringify({ ...body, signature }),
});
// → { token: "eyJ...", expires_in: 3600, scopes_granted: ["data.read"] }

What ATP protects against

ATP is designed for autonomous agents — no human is around to notice anomalies, so every primitive is conservative by default.

HMAC signing

Every request carries an HMAC-SHA256 signature over its canonicalised body. The server rejects any body that does not match.

Constant-time compare

Both signature and JWT verification use crypto.timingSafeEqual to prevent timing-leak attacks.

Short-lived tokens

Default TTL is one hour. Lost or leaked tokens expire fast. Lifecycle manager re-requests automatically.

Scoped access

Agents request only the scopes they need. The issuer rejects unknown scopes before issuing the JWT.

Stable identity

Hardware UUID fingerprint means audit logs can attribute every request to a specific machine.

Secret rotation

Rotate ATP_SECRET on the server and update the env var on agents. All new tokens use the new secret immediately.