Hardening Your Webhook
Rate limits, backoff, and budget alerts that keep a runaway agent from burning your webhook's quota — Token Vault's defaults plus the Cloudflare-side rules worth adding.
Your webhook is the data plane: every credential fetch and proxied call lands on infrastructure you pay for. A crash-looping container that re-fetches a credential on every restart can burn a Cloudflare Worker's daily quota in minutes — fully authenticated, policy-passing traffic, so nothing about it looks like an attack. This guide covers the layers that stop that, from the defaults Token Vault enforces for you to the Cloudflare rules you should add yourself.
What Token Vault already enforces
These floor limits are on by default for every account — no policy setup required:
| Path | Default limit | On exceed |
|---|---|---|
GET /api/agents/credentials | 60/min per agent | 429 + Retry-After |
MCP proxy (/api/proxy/mcp) | 300/min per proxy | 429 + Retry-After |
POST /api/tokens/{service}/refresh | 10/hour per service | 429 + Retry-After |
Repeated rejections — invalid keys, policy denials, expired grants — escalate into a penalty box: each strike doubles a lockout (1s up to 15 minutes) during which requests are refused immediately, before any policy evaluation or webhook traffic. One successful request clears it.
Token Vault also protects your webhook from itself: a 429 from your webhook is never retried (the Retry-After you send is propagated to the calling agent), and after repeated failures Token Vault opens a circuit breaker and stops calling your webhook entirely for a cool-off window.
Want tighter limits for a specific agent or token? Attach a rate_limit policy — the stricter of the two applies.
Have your webhook return 429
Since spec 2.5, the webhook contract includes 429 as a first-class response: send it with a Retry-After header (seconds) and Token Vault backs off instead of retrying. The TypeScript reference webhook ships this as a per-isolate token bucket — enable it with one env var:
# wrangler.toml
[vars]
TV_RATE_LIMIT_PER_MINUTE = "300"Each Workers isolate counts alone, so treat this as damage-bounding, not a global limit.
Add a Cloudflare rate-limiting rule
The durable, global limit lives at Cloudflare's edge, in front of your Worker — it works even for traffic that never touches Token Vault (agents follow a 307 redirect and then talk to your webhook directly, so their retries are invisible to Token Vault).
Dashboard → your zone → Security → WAF → Rate limiting rules (the free plan includes one rule):
- If: hostname equals your webhook host
- Rate: 300 requests / 1 minute per IP (match
TV_RATE_LIMIT_PER_MINUTE) - Then: Block for 1 minute
Set a budget alert
Rate limits bound the damage; an alert tells you it's happening. On Cloudflare: Notifications → Add → Usage Based Billing / Workers usage and set a threshold well below the quota you'd care about. On Cloud Run or Lambda, use the platform's budget alerts. Pair it with the activity log in the Token Vault dashboard — a rate-limited agent shows up there immediately.
Client-side: the tvault CLI backs off for you
tvault honors Retry-After on 429 with exponential backoff, fails fast (exit code 7) when the wait exceeds 10 seconds, and never retries mutating requests. If you script credential fetches yourself, do the same: treat 429 as "sleep, then retry", not as an error to loop on.
Deploy Your Own Webhook Locally with ngrok
Step-by-step guide to deploying a Token Vault webhook server locally using Docker and ngrok, binding it to your vault, and storing your first credential.
Raw Credential Brokering
Broker raw credentials (GCP service accounts, AWS credentials) through Token Vault — they live on your webhook, which mints short-lived access tokens for agents.