API / Auth / MCP Hard

OAuth Protected Resource: where an agent goes to get a token

What OAuth Protected Resource Metadata (RFC 9728) is, why agents need it, a minimal example, right vs wrong, mistakes, and how to verify.

Updated:

What it is

OAuth Protected Resource Metadata (RFC 9728) is JSON at /.well-known/oauth-protected-resource where a protected resource (your API) declares: which authorization servers issue tokens for it, which scopes are needed, and how to present the token. It’s the counterpart to OAuth Discovery: discovery describes the authorization server, this describes the protected resource.

Why it matters for AI agents

An agent hits your API and gets a 401. Now what? Without metadata it doesn’t know where to get a token. RFC 9728 answers: here are the authorization_servers, go there. Discovery + protected-resource together let an agent run the whole OAuth flow autonomously. This is exactly the scheme modern MCP uses for authorization.

Minimal working example

GET /.well-known/oauth-protected-resource HTTP/1.1
{
  "resource": "https://api.example.com",
  "authorization_servers": ["https://example.com"],
  "scopes_supported": ["read", "write"],
  "bearer_methods_supported": ["header"]
}

Plus, on a 401, the resource points to where its metadata lives:

WWW-Authenticate: Bearer resource_metadata="https://api.example.com/.well-known/oauth-protected-resource"

Right vs wrong

RightWrong
resource = the API’s canonical URLA mismatch with the real address
authorization_servers point to a valid RFC 8414 serverA link to a server with no discovery
401 + WWW-Authenticate with resource_metadataA 401 with no hint where the metadata is
Absolute HTTPS URLsRelative/HTTP

Common mistakes

  • authorization_servers points to a server with no OAuth Discovery — the chain breaks.
  • No WWW-Authenticate with resource_metadata on a 401 — the agent can’t find the entry point.
  • resource ≠ the actual URL — the client rejects the token (audience mismatch).
  • Declared scopes the server doesn’t issue.

How to verify

A scan checks for valid metadata. Manually:

curl -s https://api.example.com/.well-known/oauth-protected-resource | jq .
curl -sI https://api.example.com/ | grep -i www-authenticate

Expect valid JSON with resource and authorization_servers.

Sources