# Revocation and one consent

October 1, 2026 · API · Breaking

Servers that act for many people get the standard OAuth pieces they expect: revocation, one consent for both resources, discovery that names the right resource, and a challenge header on a refused person credential.

## What changed

- **Token revocation.** `POST /v1/oauth/revoke` takes a refresh token or an access token with your `client_id` and ends that person's connection to your client, on the API and on MCP. An expired access token still works for this. It is advertised as `revocation_endpoint` in the authorization server metadata.
- **One authorization for both resources.** Send `resource=https://api.layout.link` and `resource=https://mcp.layout.link` on one authorize request. The person approves once, one refresh token covers both, and each token request names the one resource its access token is for. Keep one refresh token for the person, not one per resource, and refresh one at a time.
- **Discovery names the API.** `https://api.layout.link/.well-known/oauth-protected-resource` now describes the REST API, with `"resource": "https://api.layout.link"`. MCP clients keep reading `https://mcp.layout.link/.well-known/oauth-protected-resource`, which has not changed.
- **A real `WWW-Authenticate` on API refusals.** A 401 from an endpoint that takes a person's credential (places, menus, images, carts, orders, profile and whoami) now carries `WWW-Authenticate` itself, with `resource_metadata` pointing at the API's metadata. Endpoints that take only your application secret answer 401 without it.
- **MCP refusals use the API's error envelope.** A 401, 403 or 503 from `mcp.layout.link`, before the request reaches the protocol, is now `{ "error": { "code", "message" } }`. The `WWW-Authenticate` challenge is unchanged.
- **A retried refresh keeps the connection.** Retrying a refresh within 20 seconds, for instance after its response was lost, now returns a new pair instead of ending the connection.
- **A disconnect stops MCP tokens at once.** When a person disconnects your app, you revoke their connection, or you delete the client, an MCP access token already issued is refused on its next request, as on the API, instead of working until it expires.

## Why it matters

When someone signs out of your product, you can end their Layout connection from your server instead of asking them to disconnect in Layout. A server that uses both the API and MCP no longer needs two consent screens. And a standard OAuth client library can now discover the API and read its challenges without special cases.

## What to do

Nothing is required. To revoke on sign-out, or to ask for both resources at once, see [Revoking a connection](https://developer.layout.link/reference/authentication#revoking-a-connection) and [One authorization for both](https://developer.layout.link/reference/authentication#one-authorization-for-both). Refresh lifetimes and rotation are spelled out in [Tokens and refresh](https://developer.layout.link/reference/authentication#tokens-and-refresh).

## Breaking changes

- The body of an MCP 401 was `{ "error": "unauthenticated" }` and is now `{ "error": { "code": "unauthorized", "message": "…" } }`. If your code reads that body, switch on `error.code`. MCP clients that follow the `WWW-Authenticate` header are unaffected.
- The API's protected resource metadata no longer names `https://mcp.layout.link`. If you read MCP's metadata from the API's origin, read it from `https://mcp.layout.link` instead.
- An MCP access token for a disconnected person or a deleted client is now refused on its next request rather than up to ten minutes later.
