Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified public/og-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/og/checklist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/og/spec.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/og/spec/well-known.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/content/changelog/2026-07-08-oauth-protected-resource.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: Added pages on OAuth 2.0 discovery metadata
date: "2026-07-08"
type: added
relatedSlugs: [oauth-protected-resource, oauth-authorization-server]
---

Added two pages completing the OAuth 2.0 discovery set: [`/.well-known/oauth-protected-resource`](/spec/well-known/oauth-protected-resource/) (RFC 9728), the metadata document naming the authorisation server(s) that issue tokens for a protected resource — now required of authenticated MCP servers — and [`/.well-known/oauth-authorization-server`](/spec/well-known/oauth-authorization-server/) (RFC 8414), the plain-OAuth sibling of [`openid-configuration`](/spec/well-known/openid-configuration/) for authorisation servers with no OpenID Connect layer. Both are `optional`: they apply only if you expose an OAuth-protected resource or run an authorisation server.
2 changes: 1 addition & 1 deletion src/content/spec/agent-readiness/mcp-and-tool-discovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ summary: "The Model Context Protocol is an emerging way for sites to expose quer
status: optional
order: 80
appliesTo: [all]
relatedSlugs: [agent-readiness-overview, machine-readable-formats, llms-txt, link-headers, api-catalog, agent-skills-discovery, a2a-agent-cards, webmcp, nlweb, agentic-resource-discovery]
relatedSlugs: [agent-readiness-overview, machine-readable-formats, llms-txt, link-headers, api-catalog, agent-skills-discovery, a2a-agent-cards, webmcp, nlweb, agentic-resource-discovery, oauth-protected-resource]
updated: "2026-06-17T00:00:00.000Z"
sources:
- title: "Model Context Protocol"
Expand Down
73 changes: 73 additions & 0 deletions src/content/spec/well-known/oauth-authorization-server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: "/.well-known/oauth-authorization-server"
slug: oauth-authorization-server
category: well-known
summary: "A JSON metadata document describing a plain OAuth 2.0 authorisation server's endpoints and capabilities. The non-OIDC sibling of openid-configuration; only needed if you run an authorisation server."
status: optional
order: 31
appliesTo: [all]
relatedSlugs: [openid-configuration, oauth-protected-resource, well-known-overview]
updated: "2026-07-08T00:00:00.000Z"
sources:
- title: "RFC 8414 — OAuth 2.0 Authorization Server Metadata"
url: "https://www.rfc-editor.org/rfc/rfc8414"
publisher: "IETF"
- title: "RFC 9728 — OAuth 2.0 Protected Resource Metadata"
url: "https://www.rfc-editor.org/rfc/rfc9728"
publisher: "IETF"
- title: "OpenID Connect Discovery 1.0"
url: "https://openid.net/specs/openid-connect-discovery-1_0.html"
publisher: "OpenID Foundation"
- title: "IANA — Well-Known URIs Registry"
url: "https://www.iana.org/assignments/well-known-uris/well-known-uris.xhtml"
publisher: "IANA"
---

## What it is

`/.well-known/oauth-authorization-server` is a JSON metadata document, defined by **RFC 8414**, that an OAuth 2.0 **authorisation server** publishes to describe itself: where to send authorisation requests, where to exchange tokens, which scopes and grant types it supports, and where its signing keys live (`jwks_uri`).

It is the plain-OAuth sibling of [`/.well-known/openid-configuration`](/spec/well-known/openid-configuration/). The two carry almost the same fields — OpenID Connect Discovery came first, and RFC 8414 was modelled on it — but they describe different servers. Publish `openid-configuration` if you are an **OpenID Connect** provider (you issue `id_token`s and expose a UserInfo endpoint); publish `oauth-authorization-server` if you are a **plain OAuth 2.0** authorisation server with no OIDC layer. A server that is both may publish both.

## Why it matters

- **Zero hand-configuration.** A client needs only your issuer URL and discovers every endpoint from this document.
- **It completes the discovery chain.** A protected resource's [`oauth-protected-resource`](/spec/well-known/oauth-protected-resource/) metadata (RFC 9728) lists its `authorization_servers`; the client fetches this document from each to find the token endpoint. Resource metadata says _who_ issues tokens; this says _how_ to get one.
- **Key rotation and capability negotiation.** `jwks_uri` is the canonical key source, and `scopes_supported` / `grant_types_supported` tell clients what you allow.

Only publish it if you actually run an authorisation server. An application that merely _consumes_ OAuth — "sign in with someone else's provider" — is a client, not a server, and has nothing to advertise here.

## How to implement

Serve the document as `application/json` over HTTPS. A minimal payload:

```json
{
"issuer": "https://login.example.com",
"authorization_endpoint": "https://login.example.com/oauth2/authorize",
"token_endpoint": "https://login.example.com/oauth2/token",
"jwks_uri": "https://login.example.com/oauth2/jwks",
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"scopes_supported": ["read", "write"]
}
```

The one rule that trips people up: for an issuer that has a **path component**, RFC 8414 _inserts_ the well-known segment before the path — issuer `https://example.com/tenant1` → `https://example.com/.well-known/oauth-authorization-server/tenant1` — whereas OIDC _appends_ it (`https://example.com/tenant1/.well-known/openid-configuration`). Get this wrong and multi-tenant clients cannot find you.

Otherwise the mechanics match [`openid-configuration`](/spec/well-known/openid-configuration/): keep `issuer` an exact match for the URL clients use, serve over HTTPS, return `200`, cache for minutes-to-hours, and let it through any authentication middleware.

## Common mistakes

- An `issuer` value that does not match the URL clients use — differing by a trailing slash, port, or hostname casing. The single most common "invalid issuer" cause.
- Using OIDC's _append_ rule instead of RFC 8414's _insert_ rule for path-bearing issuers.
- Publishing it when you only consume OAuth. That makes you a client, not a server.
- Serving it as `text/html` or behind authentication.

## Verification

```
curl -s https://login.example.com/.well-known/oauth-authorization-server | jq .
```

The response should be valid JSON with at least `issuer`, `authorization_endpoint`, `token_endpoint`, and `jwks_uri`. The `issuer` value must equal the URL prefix you advertise to clients.
75 changes: 75 additions & 0 deletions src/content/spec/well-known/oauth-protected-resource.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
title: "/.well-known/oauth-protected-resource"
slug: oauth-protected-resource
category: well-known
summary: "A JSON metadata document that tells clients which authorisation server issues the tokens an OAuth-protected API accepts, and how to present them. Only needed if you expose an OAuth-protected resource."
status: optional
order: 32
appliesTo: [all]
relatedSlugs: [openid-configuration, oauth-authorization-server, well-known-overview, mcp-and-tool-discovery, webauthn]
updated: "2026-07-08T00:00:00.000Z"
sources:
- title: "RFC 9728 — OAuth 2.0 Protected Resource Metadata"
url: "https://www.rfc-editor.org/rfc/rfc9728"
publisher: "IETF"
- title: "RFC 8414 — OAuth 2.0 Authorization Server Metadata"
url: "https://www.rfc-editor.org/rfc/rfc8414"
publisher: "IETF"
- title: "IANA — Well-Known URIs Registry"
url: "https://www.iana.org/assignments/well-known-uris/well-known-uris.xhtml"
publisher: "IANA"
- title: "Model Context Protocol — Authorization"
url: "https://modelcontextprotocol.io/specification/draft/basic/authorization"
publisher: "Anthropic / MCP"
---

## What it is

`/.well-known/oauth-protected-resource` is a JSON metadata document that an OAuth 2.0 **protected resource** — an API, or any endpoint that requires an access token — publishes so a client can discover, with no hand-configuration, which authorisation server issues the tokens it accepts and how to present them. It is defined by **RFC 9728**.

It is the resource-server counterpart to the authorisation-server documents at `/.well-known/oauth-authorization-server` (RFC 8414) and [`/.well-known/openid-configuration`](/spec/well-known/openid-configuration/). Those describe where to _get_ a token; this describes what a specific resource _expects_.

## Why it matters

- **Zero hand-configuration.** A client that receives a `401` from a protected resource can learn, from this one document, exactly which authorisation server to send the user to.
- **The 401 handshake.** The resource returns `WWW-Authenticate: Bearer resource_metadata="https://api.example.com/.well-known/oauth-protected-resource"`, so even a client that did not know the path is pointed straight at it.
- **Many issuers, one resource.** `authorization_servers` can list several trusted issuers; the client picks the right one instead of guessing.
- **Agent readiness.** The Model Context Protocol's authorization spec **requires** a remote (authenticated) MCP server to publish this document, and MCP clients use it to bootstrap OAuth. See [MCP and tool discovery](/spec/agent-readiness/mcp-and-tool-discovery/).

Only publish this if you actually expose an OAuth-protected resource. A public, unauthenticated API or MCP endpoint has nothing to advertise here — like `openid-configuration`, it is `optional` and applies only when the condition holds. (This site's own MCP endpoint is public and unauthenticated, so it does not serve this file.)

## How to implement

Serve the document as `application/json` from the resource's origin. A minimal payload:

```json
{
"resource": "https://api.example.com",
"authorization_servers": ["https://login.example.com"],
"scopes_supported": ["read", "write"],
"bearer_methods_supported": ["header"],
"jwks_uri": "https://api.example.com/.well-known/jwks.json"
}
```

Rules:

- The `resource` value must **exactly match** the resource identifier that appears in the `aud` (audience) claim of issued tokens, scheme and all.
- List every issuer you accept in `authorization_servers`. The client fetches each one's own metadata (RFC 8414 / OIDC) to find the token endpoint.
- On a `401`, set `WWW-Authenticate` with a `resource_metadata` parameter pointing at this URL, so discovery works without out-of-band configuration.
- Serve over **HTTPS**, return **200**, and let it through any authentication middleware — a discovery document hidden behind the very login it describes is useless.

## Common mistakes

- A `resource` value that does not match the `aud` claim in issued tokens — clients reject the mismatch.
- Omitting the `WWW-Authenticate: … resource_metadata=…` pointer, so only clients that already know the path can find it.
- Confusing this (the **resource server**) with `oauth-authorization-server` / `openid-configuration` (the **authorisation server**). They describe different roles.
- Serving the file behind authentication, or as `text/html`.

## Verification

```
curl -s https://api.example.com/.well-known/oauth-protected-resource | jq .
```

The response should be valid JSON with at least `resource` and `authorization_servers`. Trigger a `401` from the resource and confirm the `WWW-Authenticate` header carries a `resource_metadata` link back to this document.
2 changes: 1 addition & 1 deletion src/content/spec/well-known/openid-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ summary: "A JSON discovery document that describes an OpenID Connect provider's
status: optional
order: 30
appliesTo: [all]
relatedSlugs: [well-known-overview]
relatedSlugs: [well-known-overview, oauth-authorization-server, oauth-protected-resource]
updated: "2026-05-29T09:13:20.000Z"
sources:
- title: "OpenID Connect Discovery 1.0"
Expand Down
4 changes: 3 additions & 1 deletion src/content/spec/well-known/well-known-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ summary: "The /.well-known/ path prefix is a standardised place to publish site-
status: recommended
order: 10
appliesTo: [all]
relatedSlugs: [change-password, openid-configuration, webfinger, apple-app-site-association, assetlinks-json, nodeinfo, api-catalog, webauthn]
relatedSlugs: [change-password, openid-configuration, oauth-authorization-server, oauth-protected-resource, webfinger, apple-app-site-association, assetlinks-json, nodeinfo, api-catalog, webauthn]
updated: "2026-06-08T12:00:00.000Z"
sources:
- title: "RFC 8615 — Well-Known Uniform Resource Identifiers (URIs)"
Expand Down Expand Up @@ -38,6 +38,8 @@ The names allowed under `/.well-known/` are not arbitrary. IANA maintains a publ
- **Interoperability.** Standardised paths are what let Mastodon, Apple, Google, OpenID Connect, ACME (Let's Encrypt) and others work across millions of sites without coordination.
- **Stability.** The reserved prefix keeps protocol metadata out of the way of your application's routing. You will not accidentally collide with `/security.txt` if it lives under `/.well-known/`.

Some capabilities span **several** well-known URIs that reference each other, so a client can follow the chain with no prior configuration. OAuth 2.0 discovery is the clearest example: a protected resource describes itself at [`/.well-known/oauth-protected-resource`](/spec/well-known/oauth-protected-resource/) and names its authorisation server(s), whose own metadata lives at [`/.well-known/oauth-authorization-server`](/spec/well-known/oauth-authorization-server/) — or [`/.well-known/openid-configuration`](/spec/well-known/openid-configuration/) for OpenID Connect.

## How to implement

- Serve the resource over **HTTPS** on the canonical host.
Expand Down
Loading