# Web Bot Auth: signed agent requests a site can verify

> RFC 9421 with Ed25519: the mechanism that lets a site verify which agent is calling rather than guessing from a user-agent string.

- Source: /checks/webbotauth
- Site: AgenticWebScore
- Language: English

---
RFC 9421 with Ed25519: the mechanism that lets a site verify which agent is calling rather than guessing from a user-agent string. Adoption in the curated corpus we measured is around one site in a hundred.

| Property | Value |
| --- | --- |
| Check id | `webbotauth` |
| Dimension | Bot Access Control (18%) |
| Tier | Essential — pool 80 pts |
| Weight inside tier | 3 |
| Impact | Critical |
| Maturity | Draft — A published specification that is not yet ratified. |
| Conditional | No |
| Publishing skill | `web-bot-auth` |
| Standards | RFC 9421 |

## What the scanner requests

- `/.well-known/http-message-signatures-directory`

## What is measured

The scanner issues GET https://<domain>/.well-known/http-message-signatures-directory and expects HTTP 200 with a JWK Set: a top-level keys array in which at least one entry is a usable Ed25519 verification key (kty "OKP", crv "Ed25519", a base64url 32-byte x, and a kid) that RFC 9421 Signature and Signature-Input verification can resolve. It passes when such a key is published, returns partial when the endpoint answers 200 with parseable JSON but no usable Ed25519 key (empty keys array, missing x, wrong crv, or an RSA-only set), and fails on a non-200, an HTML body or unparseable JSON.

## Reproduce it yourself

You do not have to take our word for any of this. Run the same measurement against your own domain:

```bash
DOMAIN="example.com"
curl -sSL -o /tmp/wba.json -w 'HTTP %{http_code} %{content_type}\n' "https://$DOMAIN/.well-known/http-message-signatures-directory"; grep -Eo '"(kid|kty|crv|x)"[[:space:]]*:[[:space:]]*"[^"]*"' /tmp/wba.json | sort -u
```

## The fix

This is the artifact to ship. It is the complete change, not a description of one.

```json
{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "K6zqFKAe5fHfdzecJiq7nnGe0teq-_bhC1eP_fGo5bc",
      "kid": "2026-10-primary",
      "use": "sig",
      "alg": "Ed25519"
    }
  ]
}
```

> Serve this file over HTTPS at /.well-known/http-message-signatures-directory (application/json is fine; deployments in the wild also use application/http-message-signatures-directory+json), and replace x with the base64url of your own Ed25519 public key (openssl genpkey -algorithm ED25519) so that the private key stays in your signer.

## Standards referenced

- `RFC 9421`

## Related checks

| Check | Tier | Impact | Same skill |
| --- | --- | --- | --- |
| `agent-permissions` — Agent permission model (agent-permissions.json) | Essential | Critical | — |
| `ai-rules` — Named AI bot rules in robots.txt | Essential | High | — |
| `ai-policy` — AI usage policy page | Essential | High | — |
| `bot-page` — Crawler and agent policy page | Recommended | Medium | — |
| `security-txt` — security.txt (RFC 9116) | Recommended | Low | — |
| `crawl-delay` — Crawl rate declaration | Emerging | Low | — |
| `ai-txt` — /ai.txt access declaration | Emerging | Low | — |
