# Web Bot Auth

> OpenWAF Browsers signs every request with Web Bot Auth so sites can verify an agent is visiting. How it works, how a site verifies it and how to turn it off.

Web Bot Auth is an IETF draft that lets a bot or agent prove who it is with a cryptographic signature on each request, instead of a User-Agent string anyone can copy. It is built on HTTP Message Signatures (RFC 9421). OpenWAF Browsers signs the requests of every browser **by default**.

## What a signed request carries

Chrome's own headers and User-Agent are unchanged. Three headers are added:

```http
Signature-Agent: "https://browsers.openwaf.dev"
Signature-Input: sig1=("@authority" "signature-agent");created=1761732000;keyid="…";alg="ed25519";expires=1761732300;nonce="…";tag="web-bot-auth"
Signature: sig1=:…:
```

| Header | Meaning |
|---|---|
| `Signature-Agent` | Who signs: the origin `https://browsers.openwaf.dev`, where the public key is published. |
| `Signature-Input` | What is signed and how: the host of the request (`@authority`) and the `Signature-Agent` header, an Ed25519 key (`alg="ed25519"`), the key id (its RFC 7638 JWK thumbprint), a creation time, an expiry 5 minutes later, a random nonce and the tag `web-bot-auth`. |
| `Signature` | The Ed25519 signature over those components. |

The headers are added inside the browser to every HTTP and HTTPS request it makes: page loads, frames, subresources, `fetch` and XHR. WebSocket connections and requests made internally by service workers may not carry them.

## Key directory

The public key is published as a JSON Web Key Set at:

```text
https://browsers.openwaf.dev/.well-known/http-message-signatures-directory
```

It is served with the media type `application/http-message-signatures-directory+json`:

```json
{"keys": [{"kty": "OKP", "crv": "Ed25519", "x": "…", "kid": "…"}]}
```

The `kid` matches `keyid` in `Signature-Input`.

## Verify it on your site

A site that wants to recognise OpenWAF Browsers, to allow it, rate-limit it separately or simply count it:

1. Read `Signature-Agent` and check it is `"https://browsers.openwaf.dev"`.
2. Fetch the key directory (cache it; it rarely changes) and pick the key whose `kid` equals `keyid`.
3. Rebuild the signature base from `@authority` (the request's host, lowercase, without a default port), the `Signature-Agent` value and the `Signature-Input` parameters, as RFC 9421 describes, and verify the Ed25519 signature.
4. Reject it if `expires` is in the past, or if `created` is too far in the future. Optionally remember nonces to refuse replays.


Libraries that implement Web Bot Auth verification do steps 2 to 4 for you. Sites behind OpenWAF already check Web Bot Auth signatures as one of the [bot verification](https://developers.openwaf.dev/ai-crawl-control/verification/) methods of AI Crawl Control.

A valid signature tells you the request came from a browser run by OpenWAF Browsers. It does not tell you which customer runs it, and it does not mean the request is welcome: what to do with it is your decision.

## Turn it off

We recommend keeping it on. A signed request is honest about being automated, so sites can let it in on purpose instead of guessing, and a site that blocks it has made a clear choice you should respect. Some sites will treat signed agents better than anonymous traffic.

If you have a reason to turn it off:

- **For one browser:** start it with `"webBotAuth": false`:

  ```sh
  curl -sS -X POST https://browsers.openwaf.dev/v1/browsers \
    -H "X-API-Key: $OPENWAF_BROWSERS_KEY" -H "Content-Type: application/json" \
    -d '{"webBotAuth": false}'
  ```

- **As the organization's default:** an admin turns off **Web Bot Auth** in **Browsers → Settings**, sends `PATCH /v1/orgs/{org}/browsers/settings` with `{"web_bot_auth": false}`, runs `openwaf-cloud ctl browsers settings --web-bot-auth off --reason "…"`, or uses the `browser_settings` MCP tool. New browsers are then unsigned unless they ask for `"webBotAuth": true`.

Turning signing off does not make a browser stealthy: it is still unmodified Chrome with its own User-Agent, from OpenWAF's addresses. See [what it is not](https://developers.openwaf.dev/browsers/what-it-is-not/).
