API / Auth / MCP

OAuth Protected Resource (RFC 9728)

Metadata document /.well-known/oauth-protected-resource telling AI agents where to obtain an access token.

What is OAuth Protected Resource?

OAuth Protected Resource Metadata (RFC 9728) is a JSON document at /.well-known/oauth-protected-resource that describes a protected API resource and tells AI agents which Authorization Server to obtain an access token from.

{
  "resource": "https://api.example.com",
  "authorization_servers": [
    "https://auth.example.com"
  ],
  "scopes_supported": ["read", "write"],
  "bearer_methods_supported": ["header"]
}

Why do you need OAuth Protected Resource?

When an AI agent calls an API and receives 401 Unauthorized, it must locate the Authorization Server on its own. RFC 9728 standardizes this discovery step in two ways:

  1. The server returns a WWW-Authenticate: Bearer as_uri="https://auth.example.com" header.
  2. The agent checks /.well-known/oauth-protected-resource directly.

Without this document, an agent cannot complete authorization autonomously — it requires manual configuration. The MCP specification requires RFC 9728 support for MCP servers that use OAuth.

How do you implement OAuth Protected Resource?

Publish a static JSON file with Content-Type: application/json at /.well-known/oauth-protected-resource. Required fields:

FieldTypeDescription
resourcestring (URI)URI of the protected resource itself
authorization_serversarrayList of Authorization Server URLs
scopes_supportedarraySupported OAuth scopes
bearer_methods_supportedarrayToken delivery methods (header, body, query)

Full discovery flow for an MCP server with authorization:

GET /.well-known/oauth-protected-resource
→ { "authorization_servers": ["https://auth.example.com"], ... }

GET https://auth.example.com/.well-known/oauth-authorization-server
→ { "token_endpoint": "...", "authorization_endpoint": "..." }

POST .../token  →  access_token
GET /api/resource  (Authorization: Bearer <token>)

How do we check OAuth Protected Resource?

The scanner performs a GET request to /.well-known/oauth-protected-resource and verifies:

  • HTTP status 200 and valid JSON
  • Presence of required fields: resource, authorization_servers, scopes_supported
  • Non-empty authorization_servers array

If any condition fails, the oauth_protected_resource check returns fail. The actual authorization flow against the obtained token is not executed.

Sources and specifications