Copy the signed request from Visa's Trusted Agent Protocol spec into a unit test, run it through an Ed25519 verifier, and it fails. Mastercard's Agent Pay example fails too. Both reuse a signature from an IETF test vector that signs a different message, and both set a 60-minute validity window that breaks the 8-minute limit each network tells merchants to enforce.
Web Bot Auth, Visa TAP and Mastercard Agent Pay are how an AI agent proves who it is to a merchant's website in 2026. All three sit on RFC 9421 HTTP Message Signatures, and they disagree on tags, windows, nonces and the syntax of a single header. This guide shows a real signed request, the signature base a verifier rebuilds, and verification code that copes with all three.
What Is Web Bot Auth?
Web Bot Auth gives bots and AI agents a cryptographic identity at the HTTP layer. The agent operator signs each request with a private key and publishes the public key in a directory. The site verifies the signature and knows which operator sent it, with no shared secret and no change to TLS.
It is still a draft. The IETF chartered the webbotauth working group on 23 October 2025, and its only adopted document is draft-ietf-webbotauth-httpsig-protocol-00, published 1 September 2026 by authors from Cloudflare and Google. Adoption was contested: the poll at IETF 126 came out 22 yes, 6 no, 5 no opinion.
Deployment has run ahead of the standard anyway. Cloudflare, Akamai, AWS WAF, Vercel and HUMAN verify signatures; ChatGPT's cloud browser, Google-Agent and AWS AgentCore Browser send them. On 23 October 2026 IANA registered ml-dsa-44, ml-dsa-65 and ml-dsa-87 for HTTP Message Signatures, though Cloudflare and AWS WAF still accept Ed25519 only.
How Does Web Bot Auth Work? A Signed Request, Line by Line
These headers are the current draft's own example (Appendix E.2.1), with line wrapping removed:
Signature-Agent: agent2="https://signature-agent.test"
Signature-Input: sig2=("@authority" "signature-agent";key="agent2");created=1735689600;keyid="poqkLGiymh_W0uP6PZFw-dvez3QJT5SolqXBCW38r0U";alg="ed25519";expires=4889289600;nonce="n9p433xm+NJ3ph3upfBIGmsuwHw387YV7Q/F+6BSpGCVjYCqQw6rznNA8PVVLySrAWsv0hQtFioQb6E1YsauiA==";tag="web-bot-auth"
Signature: sig2=:RdNFx5Bj6au3YgAMQL/RzmUlZE8QZLIaXGRpw985hWnwPfMxT228NMk6ehRS1PSl4e8PhbNZACSanGdhEwYCCg==:
The verifier does not check the headers directly. It rebuilds a signature base, one line per covered component, with @signature-params required as the last line:
"@authority": example.com
"signature-agent";key="agent2": "https://signature-agent.test"
"@signature-params": ("@authority" "signature-agent";key="agent2");created=1735689600;keyid="poqkLGiymh_W0uP6PZFw-dvez3QJT5SolqXBCW38r0U";alg="ed25519";expires=4889289600;nonce="n9p433xm+NJ3ph3upfBIGmsuwHw387YV7Q/F+6BSpGCVjYCqQw6rznNA8PVVLySrAWsv0hQtFioQb6E1YsauiA==";tag="web-bot-auth"
Those bytes verify against the RFC 9421 Appendix B.1.4 Ed25519 test key. I checked. The key is public, so the vector is for tests only.
What the draft requires of a signer:
-
Coverage: at least one of
@authorityor@target-uri, plus theSignature-Agentmember that belongs to this signature. -
Parameters:
created,expires, akeyidthat "MUST be a base64url JWK SHA-256 Thumbprint", andtagset toweb-bot-auth. - Expiry: "RECOMMENDED that expiry be no more than 24 hours".
- Nonce: no requirement. Earlier versions asked for a unique 64-byte nonce; the WG draft dropped it.
- Algorithms: anything registered except shared-secret HMAC, which is banned.
-
Keys: a JWKS at
/.well-known/http-message-signatures-directory, media typeapplication/http-message-signatures-directory+json, HTTPS only. Failed lookups may be cached for at most five minutes. There is no revocation.
Read the full article on tomcn.uk →
About the Author
I'm Tom Wang, an AI Developer & Fintech Developer — building AI agents, crypto payment infrastructure, and cross-border payout systems with Rust, Go, and TypeScript. Based in London, UK.
Currently open to new opportunities in fintech, crypto payments, and AI agent engineering.
Top comments (1)
the test vector detail is the part that should worry integrators most: if the spec example and the network spec disagree, which one does a verifier trust? shipping a signed request that fails an ed25519 check because it was copied from a draft appendix is exactly the kind of bug that only surfaces when a merchant's verification code goes live. the 60-minute vs 8-minute window gap is its own problem too, since a replayed signature inside a 60-minute window is valid by the letter of one spec and stale by the letter of the other. the nonce removal also deserves a flag, because it shifts replay protection onto expiry alone, which is thinner than it looks.