Skip to content

SEP-2643: Structured Authorization Denials#2643

Open
monmohan wants to merge 15 commits into
modelcontextprotocol:mainfrom
monmohan:sep-structured-authorization-denials
Open

SEP-2643: Structured Authorization Denials#2643
monmohan wants to merge 15 commits into
modelcontextprotocol:mainfrom
monmohan:sep-structured-authorization-denials

Conversation

@monmohan

@monmohan monmohan commented Apr 24, 2026

Copy link
Copy Markdown

Motivation and Context

This SEP defines a transport-agnostic JSON-RPC authorization denial envelope for the Model Context Protocol. The envelope complements transport-level authorization challenges (HTTP WWW-Authenticate with Protected Resource Metadata), carrying failure classification, a retry correlation handle, and an extensible set of structured remediation hints for cases the transport cannot easily express. This SEP defines two initial remediation hint types and illustrates their use through three scenarios: URL-based approval composed with MCP URL-mode elicitation, credential replacement using scopes and OAuth Rich Authorization Requests (RFC 9396), and additional short-lived credentials for per-transaction operations like payment initiation in banking. Further remediation hint types can be defined in follow-on SEPs without changes to the envelope.

How Has This Been Tested?

This has been reviewed in the MCP Fine-Grained Authorization Working Group over multiple review cycles.
Discord: MCP FGA WG channel
Please see the Acknowledgments section of the SEP for reviewers.

Breaking Changes

This SEP is fully backward compatible. Existing OAuth clients and libraries do not need to change as the envelope is additive.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Status: Draft — awaiting sponsor. Will coordinate with FGA WG Lead to update this
AI Assistance Disclosure:: This SEP was written by the author with AI assistance for editorial review (grammar, structural arrangement etc.)

@monmohan
monmohan requested review from a team as code owners April 24, 2026 11:22
@monmohan monmohan changed the title SEP: Structured Authorization Denials (initial draft) SEP-2643: Structured Authorization Denials Apr 24, 2026
@localden localden added proposal SEP proposal without a sponsor. SEP labels Apr 24, 2026
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md
Comment thread seps/2643-structured-authorization-denials.md
Comment thread seps/2643-structured-authorization-denials.md
Comment thread seps/2643-structured-authorization-denials.md
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated
monmohan and others added 9 commits May 13, 2026 15:56
Removes Use Case 3 (additional short-lived
  credentials) and its related artifacts (Motivation modelcontextprotocol#4, credentialDisposition envelope field, UC3-specific Security Implications
  subsection, abstract "three scenarios" framing). Adds a Rationale subsection "Future Extensions: Multi-Token Management"
  pointing to the planned authorization_hint and usage_semantics extension of draft-zehavi-oauth-rar-metadata and complementary WG
  work on client-side multi-credential handling.

Addresses PR review threads L60, L62, L64, L300.
Comment thread seps/2643-structured-authorization-denials.md Outdated
Comment thread seps/2643-structured-authorization-denials.md Outdated

This use case covers denials where the client's credential is valid and does not need to change. Remediation requires an out-of-band user interaction at a URL, such as approving access or selecting resources, that changes server-side state. A representative example is a file picker in a cloud storage service, where the user's OAuth token is unchanged and the server records an approval tied to the user.

This use case composes with the MCP URL elicitation error (`URLElicitationRequiredError`, JSON-RPC error code `-32042`). The envelope MUST include a `remediationHints` entry of type `url`, and the URL elicitation remains in `data.elicitations` for backwards compatibility.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and the URL elicitation remains in data.elicitations for backwards compatibility

Does this imply that it's in a different place going forward? Or is data.elicitations the canonical place a client should read this data from?

Comment thread seps/2643-structured-authorization-denials.md Outdated

### Use Case 2 — Credential replacement with broader authorization

This use case covers denials where the client's existing credential carries insufficient authorization for the requested operation and remediation requires obtaining a new credential. The replacement may involve additional OAuth scopes, a Rich Authorization Requests `authorization_details` object (RFC 9396), or any other mechanism that yields a new credential. In contrast with Use Case 1, the failure cannot be resolved by server-side state changes alone.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This use case covers denials where the client's existing credential carries insufficient authorization for the requested operation and remediation requires obtaining a new credential. The replacement may involve additional OAuth scopes, a Rich Authorization Requests `authorization_details` object (RFC 9396), or any other mechanism that yields a new credential. In contrast with Use Case 1, the failure cannot be resolved by server-side state changes alone.
This use case covers denials where the client's existing credential carries insufficient authorization for the requested operation and remediation requires obtaining a new credential, which may include additional OAuth scopes, a Rich Authorization Request's `authorization_details` object (RFC 9396), or any other mechanism to add required authorization to the new credential. In contrast with Use Case 1, the failure cannot be resolved by server-side state changes alone.

}
```

The client uses the `authorization_details` from the remediation hint to construct an OAuth authorization request, per [RFC 9396#section-2](https://datatracker.ietf.org/doc/html/rfc9396#section-2):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The client uses the `authorization_details` from the remediation hint to construct an OAuth authorization request, per [RFC 9396#section-2](https://datatracker.ietf.org/doc/html/rfc9396#section-2):
The client attempts to locate an existing valid credential matching a provided `authorization_reference`, if provided. If no matching credential is found, the client uses the `authorization_details` from WWW-Authenticate header's `authorization_remediation` parameter, to construct an OAuth authorization request, per [RFC 9396#section-2](https://datatracker.ietf.org/doc/html/rfc9396#section-2):


The SEP composes with existing MCP primitives rather than inventing parallel shapes. Use Case 1 reuses MCP URL elicitation (`URLElicitationRequiredError`) and adds the envelope as sibling metadata inside the same error response. Clients that already understand URL elicitation continue to work unchanged, and clients that additionally understand the envelope receive transport-agnostic classification and a correlation handle.

### Future Extensions: Multi-Token Management

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd remove this section completely.
UC2 with RAR relies on the rar-metadata draft, which now (version 03) includes the authorization_hint attribute, and was accepted at the OSW in Leipzig on 05/2026.
Therefore I've added to the SEP authorization_hint and its usage which is a one-liner actually.
Therefore I believe this comment can be removed.


2. **Support for signaling server-side state remediation**: Some authorization denials are not about the client's credential. The MCP server may deny a request because it has insufficient information to contact an external system, needs confirmation from the user, or another piece of server-side state must be established before the request can succeed. OAuth authorization challenges such as `insufficient_scope` or `invalid_token` are shaped around credential changes and do not cover this case. MCP has URL-mode elicitation as a primitive for out-of-band user interaction, but it is not itself an authorization denial signaling mechanism.

3. **Support for structured remediation data at denial**: OAuth 2.0 defines Rich Authorization Requests (RFC 9396) for conveying structured authorization requirements, but only as part of the authorization request flow. Adopted OAuth standards do not yet provide a way to carry such structured requirements back to the client at denial time. An IETF individual draft, [`draft-zehavi-oauth-rar-metadata`](https://datatracker.ietf.org/doc/draft-zehavi-oauth-rar-metadata/02/), proposes a mechanism for HTTP by defining a new `WWW-Authenticate` error code, `insufficient_authorization_details`, with the structured data placed in a JSON response body. The draft is HTTP-specific, and this SEP proposes to adopt the same pattern at the JSON-RPC layer so it applies across MCP transports.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
3. **Support for structured remediation data at denial**: OAuth 2.0 defines Rich Authorization Requests (RFC 9396) for conveying structured authorization requirements, but only as part of the authorization request flow. Adopted OAuth standards do not yet provide a way to carry such structured requirements back to the client at denial time. An IETF individual draft, [`draft-zehavi-oauth-rar-metadata`](https://datatracker.ietf.org/doc/draft-zehavi-oauth-rar-metadata/02/), proposes a mechanism for HTTP by defining a new `WWW-Authenticate` error code, `insufficient_authorization_details`, with the structured data placed in a JSON response body. The draft is HTTP-specific, and this SEP proposes to adopt the same pattern at the JSON-RPC layer so it applies across MCP transports.
3. **Support for structured remediation data at denial**: OAuth 2.0 defines Rich Authorization Requests (RFC 9396) for conveying structured authorization requirements, but only as part of the authorization request flow. Adopted OAuth standards do not yet provide a way to carry such structured requirements back to the client at denial time. An IETF individual draft, [`draft-zehavi-oauth-rar-metadata`](https://datatracker.ietf.org/doc/draft-zehavi-oauth-rar-metadata/05/), proposes a mechanism for HTTP by defining a new `WWW-Authenticate` error code, `insufficient_authorization`, with the structured data placed in the authorization_remediation header error parameter, which contains a base64url-encoded JSON object. The draft is HTTP-specific, and this SEP proposes to adopt the same pattern at the JSON-RPC layer so it applies across MCP transports.


When a denied request requires authorization beyond what OAuth scopes can express, the `WWW-Authenticate` challenge can signal that authorization is insufficient but cannot carry the structured requirements themselves. The server MAY supply those requirements inside the envelope so the client can construct its next authorization request directly, without additional metadata discovery. This approach mirrors the error-signaling pattern defined in [OAuth 2.0 RAR Metadata and Error Signaling](https://datatracker.ietf.org/doc/draft-zehavi-oauth-rar-metadata/02/) at the JSON-RPC layer.

An MCP server that denies a request because the access token lacks sufficient authorization details MAY return a `remediationHints` entry of type `oauth_authorization_details`. The entry's `authorization_details` member, when present, SHALL be an OAuth Rich Authorization Requests `authorization_details` array as defined in RFC 9396. On HTTP Transports, The server MUST still return an HTTP authorization challenge via `WWW-Authenticate`, which remains authoritative for remediation and discovery. The JSON-RPC remediation hint is supplemental and exists to carry an actionable `authorization_details` object inside the response body.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
An MCP server that denies a request because the access token lacks sufficient authorization details MAY return a `remediationHints` entry of type `oauth_authorization_details`. The entry's `authorization_details` member, when present, SHALL be an OAuth Rich Authorization Requests `authorization_details` array as defined in RFC 9396. On HTTP Transports, The server MUST still return an HTTP authorization challenge via `WWW-Authenticate`, which remains authoritative for remediation and discovery. The JSON-RPC remediation hint is supplemental and exists to carry an actionable `authorization_details` object inside the response body.
An MCP server that denies a request because the access token lacks sufficient authorization details returns a transport layer WWW-Authenticate header with appropriate remediation requirements. The client performs OAuth reauthorization using the transport challenge, obtains a new access token which includes the provided `authorization_details`, and retries the original request with the new token in the `Authorization` header. The client echoes the `authorizationContextId` per "Retry Echo via `_meta`".


An MCP server that denies a request because the access token lacks sufficient authorization details MAY return a `remediationHints` entry of type `oauth_authorization_details`. The entry's `authorization_details` member, when present, SHALL be an OAuth Rich Authorization Requests `authorization_details` array as defined in RFC 9396. On HTTP Transports, The server MUST still return an HTTP authorization challenge via `WWW-Authenticate`, which remains authoritative for remediation and discovery. The JSON-RPC remediation hint is supplemental and exists to carry an actionable `authorization_details` object inside the response body.

A client that recognizes the `oauth_authorization_details` hint MAY use the provided `authorization_details` directly in a subsequent OAuth authorization request. A client that does not recognize the hint SHOULD fall back to resource-metadata and authorization-server-metadata discovery to determine how to construct a valid authorization request.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A client that recognizes the `oauth_authorization_details` hint MAY use the provided `authorization_details` directly in a subsequent OAuth authorization request. A client that does not recognize the hint SHOULD fall back to resource-metadata and authorization-server-metadata discovery to determine how to construct a valid authorization request.
A client that recognizes the `WWW-Authenticate` header with `insufficient_authorization` error code and `authorization_remediation` parameter MAY use an existing valid credential matching a provided `authorization_reference` value, if provided. If no matching credential is found, client MAY use the provided `authorization_details` directly in a subsequent OAuth authorization request. A client that does not recognize the hint SHOULD fall back to resource-metadata and authorization-server-metadata discovery to determine how to construct a valid authorization request.


```json
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_authorization_details",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
WWW-Authenticate: Bearer error="insufficient_authorization_details",
WWW-Authenticate: Bearer error="insufficient_authorization",
resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/payments",
error_description="Additional authorization is required",
authorization_remediation=eyJhdXRob3JpemF0aW9uX2RldGFpbHMiOlt7InR5cGUiOiJkaX...

```json
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_authorization_details",
resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource/payments",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove, included above

"authorization": {
"reason": "insufficient_authorization",
"authorizationContextId": "authzctx_pay_9f2c",
"remediationHints": [

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Propose remove remediationHints, it's provided in the header

Consider an MCP server that exposes a `payments.initiate` tool where initiating a payment requires authorization details bound to the payee and amount. The client's current access token does not carry such authorization details, and the call is denied:

```json
HTTP/1.1 403 Forbidden

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
HTTP/1.1 403 Forbidden
HTTP/1.1 401 Unauthorized

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

proposal SEP proposal without a sponsor. SEP

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

5 participants