Tokens and clearances
Single-use tokens (receipts) for one operation, reusable clearances for gateway routes, and how each is bound and verified.
A passed verification gives the page a token. Actions configured for it also give a clearance. They answer different questions:
| Token (receipt) | Clearance | |
|---|---|---|
| Answers | "May this one operation happen?" | "Has this visitor passed recently?" |
| Use | Once | Any number of times until it expires |
| Lifetime | RECEIPT_TTL_SECONDS, default 120 s (30–300) | CLEARANCE_TTL_SECONDS, default 1800 s (60–86,400) |
| Bound to | site, action, origin, expiry, key | site, origin, expiry, key |
| Checked by | your server: POST /v1/siteverify, or the gateway | the gateway (/v1/gateway/check) |
| Carried in | the agentgate_token form field, or a header you choose (the gateway reads X-AgentGate-Token) | the X-AgentGate-Clearance header, or the agentgate_clearance cookie |
Tokens
A token starts with agr1. and is signed by AgentGate. Treat it as an opaque string: its format may change. It records the site, the action it was issued for, the page origin, when it was issued and expires, and the decision ID. It holds no scores or personal data.
- Single use. Redemption is atomic: of any number of concurrent redemptions, one succeeds and the others get
token_used. - Safe retries. Redeeming again with the same
requestIdwithin the token's lifetime returns the same success withidempotentRetry: true. This covers a lost response; it never authorises a second operation. - Bound to its action.
expectedActionis required at siteverify, so a token earned on a newsletter form cannot sign up an account. - Short-lived. Call
execute()(or let the widget verify) at submit time, not at page load.
Details: Validate tokens.
Clearances
For actions registered with "clearance": true (--action name:clearance on the command line), a passed verification also returns a clearance: a signed value that the gateway accepts on routes of clearance actions instead of a fresh token, until it expires. This is the "pass once, browse for a while" pattern. A clearance earned for one clearance action is accepted on the routes of every clearance action of the site, but only on the origin that earned it: the gateway compares it with the protected request's scheme and host (X-Original-Proto, X-Original-Host), so the page and the protected routes must share an origin.
AgentGate.execute() returns it as clearance, with clearanceExpiresAt (Unix milliseconds). Send it on requests the gateway protects:
const { clearance } = await AgentGate.execute({ action: "browse" });
await fetch("/api/catalog", { headers: { "X-AgentGate-Clearance": clearance } });When AgentGate's browser API is served from your own origin (you reverse-proxy /v1/browser/*), the clearance is also set as the first-party cookie agentgate_clearance (HttpOnly, SameSite=Lax, Secure over HTTPS), so the browser sends it without code. Third-party cookies are never used.
Warning
A clearance is a bearer value: it is bound to the site and origin, not to a device, and a copied value works from elsewhere until it expires. Keep the lifetime short on sensitive routes and use single-use tokens for state-changing operations.
Clearances are Ed25519-signed, so they keep verifying after a key rotation until the old key is retired.
What to send where
| You protect | The page sends | Your server does |
|---|---|---|
| A form post handled by your backend | agentgate_token field (widget) | POST /v1/siteverify |
A fetch call handled by your backend | the token, in a header or body field you choose | POST /v1/siteverify |
| A route behind the gateway, one operation | X-AgentGate-Token header | nothing: the gateway checks and spends it |
| Routes behind the gateway, repeated reads | X-AgentGate-Clearance header or the cookie | nothing: the gateway checks it |