For Agent Developers
Install AgentDOM, set the shared secret, and call requestToken. The library handles signing, persistence, and refresh.
# 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"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.
// 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:
{
"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.
| Function | What 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.
Build the request
Agent assembles { agent_id, scopes, purpose, timestamp }.
Sign it
HMAC-SHA256 over the canonicalised body using the shared secret.
POST & receive
Server verifies the signature and returns a short-lived JWT scoped to what was requested.
// 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.