# Agent authentication — webanalyzer.dev

WebAnalyzer is a free, public website analyzer. **No credentials are required for any
agent-facing surface**: the web pages, the REST API at
`https://webanalyzer.dev/api/v1`, the MCP servers
(`https://webanalyzer.dev/.well-known/mcp` and `https://webanalyzer.dev/mcp/docs`), and
the machine-readable files (`/llms.txt`, `/agents.md`, `/.well-known/ard.json`) are all
open, anonymous and rate-limited by IP. For agent stacks that *require* an OAuth flow, a
real optional one exists — it grants no extra privilege, because there is nothing gated
to unlock.

## Discover

- Protected-resource metadata (RFC 9728): `https://webanalyzer.dev/.well-known/oauth-protected-resource`
- Authorization-server metadata (RFC 8414): `https://webanalyzer.dev/.well-known/oauth-authorization-server`

The protected-resource metadata's `agent_auth` block lists both supported methods —
`anonymous` (recommended) and `oauth_client_credentials` — with the exact endpoint URIs
below. The identity endpoint is
`POST https://webanalyzer.dev/api/v1/oauth/identity` — send an identity (e.g. an email)
and it answers, machine-readably, that no identity binding exists and anonymous access
covers everything. Both documents and this file always agree; if they ever diverge, treat the
metadata as canonical and tell us at hello@webanalyzer.dev.

## Pick a method

Pick **anonymous access** (recommended). It covers everything the service offers.
Pick **client credentials** only if your framework insists on presenting a token.

## Register

Anonymous: no registration step.

Client credentials: `POST https://webanalyzer.dev/api/v1/oauth/register` (RFC 7591 —
an empty JSON object is enough; optionally send `{"client_name": "my-agent"}`). The
response contains `client_id` and `client_secret`. Registration is stateless and
instant; credentials do not expire.

## Claim

Anonymous: no claim step.

Client credentials: `POST https://webanalyzer.dev/api/v1/oauth/token` with form body
`grant_type=client_credentials&client_id=…&client_secret=…`. Returns a Bearer
`access_token` valid for 1 hour with scope `analyze`.

## Use the credential

Anonymous: send requests with no `Authorization` header at all. Example:
`POST https://webanalyzer.dev/api/v1/analyze` with `{"url": "https://example.com"}`
works as-is, as does an MCP `initialize` request to either server.

With a token: send `Authorization: Bearer <access_token>` to the same endpoints. The
response is identical — tokens exist for framework compatibility, not for access.

Full analysis reports are delivered by email on the website; that email gate is a human
product feature, not an agent auth mechanism.

## Errors

Endpoints never demand a credential, but a **presented** credential that is invalid or
expired gets `401` with
`WWW-Authenticate: Bearer resource_metadata="https://webanalyzer.dev/.well-known/oauth-protected-resource", error="invalid_token"` —
drop the header or fetch a fresh token and retry. A `429 Too Many Requests` with
`Retry-After` and standard `RateLimit-*` headers means the per-IP rate limit was hit —
wait and retry. A `422` from the analyzer means the target URL could not be fetched or
is not allowed (private/internal hosts are refused). API errors are always structured
JSON: `{"error": {"code", "message", "status"}}`.

## Revocation

`POST https://webanalyzer.dev/api/v1/oauth/revoke` with `token=<access_token>`
(RFC 7009). Tokens are short-lived and stateless, so revocation acknowledges and expiry
enforces. Anonymous access has nothing to revoke — to stop using the service, stop
sending requests.
