How to publish OAuth protected resource metadata

Follow these steps end-to-end. Use the local generator for the four artifacts; deploy them on your own resource origin.

1. Confirm prerequisites

You need deploy access on the resource origin (the host that serves your API or MCP endpoint) and a decision about which authorization server issuer URLs clients should use. This pack does not create tokens, clients, or AS metadata (RFC 8414).

2. Choose the resource identifier carefully

The resource identifier is an HTTPS URL with no fragment. Prefer no query string unless you truly need it. If the identifier includes a path (for example https://api.example.com/mcp), that path becomes part of the well-known location.

3. Fill the generator and rebuild

Open the generator. Enter the resource URL, one or more authorization server issuers, and optional scopes. Rebuild and inspect all four outputs before touching production.

4. Host JSON at the derived well-known path

For a resource with no path, publish at https://<host>/.well-known/oauth-protected-resource. For a resource with path /mcp, publish at https://<host>/.well-known/oauth-protected-resource/mcp — insert /.well-known/oauth-protected-resource between the host and the path after removing a trailing slash on the host component (RFC 9728 §3.1).

5. Keep resource byte-for-byte identical

The JSON field resource MUST match the resource identifier you used to derive the URL. Clients must reject metadata when these values differ. Do not add a trailing slash “for neatness” unless the identifier itself includes one.

6. Apply Pages _headers (or equivalent)

Copy the recipe from the tool into the root _headers of the Cloudflare Pages project that serves the resource host (or set an explicit Content-Type map on Nginx). Redeploy, then confirm the response is Content-Type: application/json. An HTML soft-404 with status 200 breaks discovery.

7. Return WWW-Authenticate on unauthenticated calls

When a client hits the resource without a token, respond with HTTP 401 and include:

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

Point resource_metadata at the absolute well-known URL you just published. Clients fetch PRM, then discover the authorization server.

8. Curl self-check

From any machine:

curl -sSI "https://<host>/.well-known/oauth-protected-resource[/path]"
curl -sS  "https://<host>/.well-known/oauth-protected-resource[/path]" | head
curl -sSI -o /dev/null -w "%{http_code}\n" -H "Authorization:" "https://<resource-url>"

Expect HTTP 200 and application/json on the well-known document, parseable JSON whose resource matches the identifier, and a 401 (or your chosen challenge) that includes resource_metadata when unauthenticated.

Private keys and client secrets never enter this site. Generation is local. See Privacy.