# Web Bot Auth vs Visa TAP: How to Verify AI Agents

> Source: <https://dev.to/tomwangcn/web-bot-auth-vs-visa-tap-how-to-verify-ai-agents-27d4>
> Published: 2026-10-26 08:39:45+00:00

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.

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.

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:

`@authority` or `@target-uri`, plus the `Signature-Agent` member that belongs to this signature.`created`, `expires`, a `keyid` that "MUST be a base64url JWK SHA-256 Thumbprint", and `tag` set to `web-bot-auth`.`/.well-known/http-message-signatures-directory`, media type `application/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 →](https://tomcn.uk/news/2026-10-26-web-bot-auth-vs-visa-tap-mastercard-agent-pay)

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.
