send.webforms.toRead the docs →

ai-agentssecurity

Web Bot Auth explained: verifying AI agents with HTTP message signatures

User agent strings are claims. A signature made with a key published on the operator's own domain is evidence. Here is how the check works, step by step.

WebForms 3 min read

Web Bot Auth lets an AI agent prove who it is by signing each request with a private key and publishing the matching public key on its operator's domain. A site verifies by reading the Signature-Agent header, fetching that domain's key directory, picking the key whose thumbprint matches the signature's keyid, rebuilding the signed parts of the request, and checking both the signature and its time window. If any step fails, the request is simply unverified.

Why not just trust the user agent?

Because it is free text. Any script can send a user agent naming a well-known assistant, and plenty do, precisely because sites treat those names kindly. IP allowlists are the traditional fix, but agents increasingly run from shared cloud ranges and residential proxies, and published IP lists go stale. A signature binds the request to a key, and the key to a domain, without either side maintaining lists.

What does a signed request look like?

Three headers carry it. Signature-Input lists what was signed and the parameters. Signature holds the signature itself. Signature-Agent says where the keys live.

Request headers
Signature-Agent: sig1="https://agent.example.com"
Signature-Input: sig1=("@authority" "signature-agent";key="sig1");
    created=1794330000;expires=1794330060;
    keyid="poqkLGiymh_W0uP6PZFw-dvez3QJT5SolqXBCW38r0U";
    tag="web-bot-auth"
Signature: sig1=:jdq0SqOwHdyHr9+r5jw3iYZH6aNGKijYp/EstF4RQTQdi5N5YYKrD+mCT1HA1nZDsi6nJKuHxUi/5Syp3rLWBA==:

The tag value web-bot-auth marks the signature's purpose. The keyid is the key's JWK thumbprint (RFC 7638), so the verifier can find the right key without trusting a name. Older deployments send Signature-Agent as a plain quoted URL rather than a dictionary member; a verifier should accept both.

How does a site verify it?

  1. Find the signature labelled with tag="web-bot-auth" in Signature-Input.
  2. Check the window: created is not in the future and expires has not passed, allowing a minute of clock skew.
  3. Check coverage: the signature must include @authority (or @target-uri) and the signature-agent header. Otherwise it could be lifted onto a different host or pointed at different keys.
  4. Resolve the key directory from Signature-Agent: an HTTPS URL, by default /.well-known/http-message-signatures-directory on that origin.
  5. Fetch the directory (a JSON Web Key Set), take the Ed25519 key whose thumbprint equals keyid, and check the key's own nbf and exp if present.
  6. Rebuild the RFC 9421 signature base from your view of the request, one line per covered component, ending with @signature-params, and verify the signature over it.

Which mistakes let forgeries through?

  • Not requiring @authority: a signature made for another site's request then verifies on yours.
  • Not requiring signature-agent to be signed: an attacker keeps a real signature and points the header at their own keys.
  • Fetching the key directory carelessly: the header is attacker-controlled, so only fetch HTTPS URLs that resolve to public addresses, cap the response size and time, and cache results so one agent costs one fetch.
  • Ignoring time: without the created and expires check, a captured request can be replayed indefinitely.
  • Failing open: a malformed header should mean unverified, never verified and never an error that blocks the request.

What does a verified signature give you?

Identity, not permission. You learn which operator sent the request, which is enough to apply a policy you choose: let a known assistant's bookings through to a separate queue, rate limit by operator rather than by IP, or keep a record of which agents act on your site. Content still needs its own checks.

Where WebForms uses it

Every form submission to WebForms is checked for a Web Bot Auth signature. A valid one tags the submission as a verified AI agent, with the operator's domain alongside, and routing rules, webhooks and the API all see it. An unsigned or invalid signature never blocks a submission; it just is not called verified, and the dashboard shows why.

Questions

What is Web Bot Auth?
Web Bot Auth is a proposed standard that lets bots and AI agents prove their identity by signing each HTTP request (RFC 9421 HTTP Message Signatures) with a key the operator publishes at its own domain.
What is the Signature-Agent header?
It names where the agent's public keys are published, as an HTTPS URL on the operator's domain. It must itself be covered by the signature, so it cannot be swapped for another domain.
Can a Web Bot Auth signature be replayed?
Only within its validity window and only to the same host, because the signature covers the target authority and carries created and expires times. Sites should reject anything outside that window.
Does a valid signature mean I should accept the request?
It means you know who sent it. Whether that operator is welcome, and whether the content is acceptable, is still your decision.

Signed agents, verified for you

WebForms checks Web Bot Auth signatures on every form submission and tags verified agents with their operator's domain. Route them, filter them, or just know.