Gateway overview

Put AgentGate in front of any HTTP app. Routes map requests to actions; GET /v1/gateway/check decides each request before it reaches your origin.

The gateway decides every protected request with the same engine as the browser widget: tokens, clearances, verified agent signatures, rate policy and the site's rules. Your proxy or middleware asks GET /v1/gateway/check before forwarding, and forwards only on a 204.

Use it when you want protection without touching each handler, for routes that browsers never call (APIs, webhooks, agents), or when the same routes serve people and agents.

1. Describe the site's routes

A site's routes map a request to an action, and the action says what evidence it needs. Set them in the console (site settings) or with the admin API:

JSON
{
  "allowedOrigins": ["https://app.example.com"],
  "actions": {
    "signup":       {"browserRequired": true},
    "checkout":     {"browserRequired": true, "clearance": true},
    "catalog_read": {"browserRequired": false},
    "agent_orders": {"browserRequired": false, "requireContentDigest": true}
  },
  "routes": [
    {"method": "POST", "path": "/api/signup", "action": "signup"},
    {"method": "POST", "path": "/checkout", "action": "checkout"},
    {"method": "GET", "pathPrefix": "/api/catalog/", "action": "catalog_read"},
    {"method": "POST", "path": "/api/orders", "action": "agent_orders"}
  ]
}
  • Browser routes (browserRequired: true) need a single-use token from the browser SDK in X-AgentGate-Token, or, for clearance: true actions, a valid clearance (X-AgentGate-Clearance or AgentGate-Clearance header, or the agentgate_clearance cookie). Without one the answer is a challenge (401).
  • Machine routes (browserRequired: false) never ask for browser evidence: rate policy, agent identity and rules only. Requests no route matches are evaluated the same way.
  • The action always comes from this configuration, never from the client. Paths are normalised like nginx: /api/./signup, /api//signup and /api/%73ignup are all /api/signup.
  • requireContentDigest: true makes a signed agent's signature cover the request body's Content-Digest (see Signed agents).

The page sends the token as a header:

JavaScript
const { token } = await AgentGate.execute({ action: "signup" });
await fetch("/api/signup", { method: "POST", headers: { "X-AgentGate-Token": token }, body });

Note

nginx auth_request never sees the request body, so a hidden form field cannot reach the gateway. For classic form posts, validate the token in your backend with /v1/siteverify instead.

2. The check API

GET /v1/gateway/check, called by your gateway only (never by browsers):

Request headerMeaning
Authorization: Bearer ags_…the site's backend secret (required)
X-AgentGate-Site-Keyoptional; must name the secret's site
X-Original-Method, X-Original-Host, X-Original-URI, X-Original-IPthe original request (required)
X-Original-Protohttp or https (default https)
X-Original-Body-Digestmatch or mismatch if the adapter checked Content-Digest against the body; omit when it never saw the body
X-AgentGate-Token, X-AgentGate-Clearance, Cookiethe client's token and clearance
Signature, Signature-Input, Signature-Agent, Content-Digest, User-Agent, …the client's own headers, forwarded

X-Original-* headers are believed only from a caller with a valid secret for the site; without one the answer is 403 invalid_credential and nothing is evaluated.

AnswerWhenHeaders
204allow; always in monitor modeX-AgentGate-Decision: allow, X-AgentGate-Reason, X-AgentGate-Decision-ID, X-AgentGate-Agent (verified agent), X-AgentGate-Would-Decision (monitor), X-AgentGate-Digest-Check: required
401challenge: get a (new) tokenX-AgentGate-Reason, for example receipt_required, token_used, expired_clearance
403block, or a bad secret or metadata (every mode)X-AgentGate-Reason, for example rate_limited, agent_signature_invalid, policy, invalid_credential
503dependency failure in enforce modeX-AgentGate-Reason: service_unavailable, Retry-After: 5

Every reason is listed on Error codes. The endpoint never answers 429; the nginx configuration maps 403 rate_limited to 429 for the client and 403 payment_required to 402. In monitor mode a failing token verifier is recorded and the request allowed with reason service_unavailable, never silently.

Rate budgets per site: GATEWAY_IP_PER_MINUTE per client address and GATEWAY_AGENT_PER_MINUTE per verified agent without its own quota (both default 600). Exceeding one labels the request; the rules decide.

When a token is spent

A token is spent only by the request it admits:

  • the check first validates it without spending it (signature, site, action and origin, expiry, not yet used), then evaluates the request;
  • only an allow spends it, in one transaction with the decision event;
  • a block or challenge after a valid token (a rate limit, a rule, a bad signature) leaves it unspent;
  • if the transaction fails, enforce mode answers 503 and the token stays unspent, so retrying the same operation with it is safe;
  • of several concurrent requests carrying one token, exactly one is allowed; the others get 401 token_used.

This is exactly-once admission at AgentGate, not exactly-once execution at your origin: if your origin fails after a 204, the token is spent and the client needs a new one.

Signed agents

Web Bot Auth signatures are verified at the gateway over @authority, @method, @path and the covered Signature-Agent member. Because auth_request never sees the body, content-digest is required only on actions with requireContentDigest: true. There the gateway checks that the signature covers it and answers X-AgentGate-Digest-Check: required, and your middleware verifies the digest against the body. A middleware that checked the body itself sends X-Original-Body-Digest instead.

3. Pick an adapter

  • nginx: auth_request in front of any app, tested against a real nginx.
  • Go and Node middleware: inside your app, with body digest checks.

4. Go live

  1. Start in monitor mode and watch the would-have decisions for false positives.
  2. Switch the site to enforce.
  3. Rotate the backend secret with an overlap window: update your gateway's secret and reload before the old one expires.

Limits: rate budgets are process-local (one AgentGate instance per state directory), and content classifiers do not run on gateway checks because the gateway sees no body.

View as Markdown