Skip to content

SEP-1932: DPoP Profile for MCP - #1932

Open
PieterKas wants to merge 32 commits into
modelcontextprotocol:mainfrom
PieterKas:patch-1
Open

PieterKas wants to merge 32 commits into
modelcontextprotocol:mainfrom
PieterKas:patch-1

Conversation

@PieterKas

@PieterKas PieterKas commented Dec 5, 2025 •

Copy link
Copy Markdown
Contributor

Motivation and Context

This extension defines DPoP (Demonstrating Proof-of-Possession) support for the Model Context Protocol, enabling sender-constrained access tokens that prevent token replay attacks. This extension builds upon the baseline authorization requirements defined in the main Authorization specification.

DPoP binds access tokens to a cryptographic key pair controlled by the client. When accessing MCP server resources, clients must prove possession of the private key by providing a signed proof with each request. This prevents unauthorized use of tokens even if they are intercepted or leaked.

How Has This Been Tested?

TBD

Breaking Changes

No

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • [ x] 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

For inclusion as an auth extension

@D-McAdams

@PieterKas PieterKas changed the title Create 0000-dpop-extension.md 1932-dpop-extension.md Dec 5, 2025
@PieterKas PieterKas changed the title 1932-dpop-extension.md SEP-1932: DPoP Profile for MCP Dec 5, 2025
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@D-McAdams D-McAdams self-assigned this Dec 8, 2025
@D-McAdams D-McAdams added auth SEP draft SEP proposal with a sponsor. extension labels Dec 8, 2025
@D-McAdams
D-McAdams requested a review from a team December 8, 2025 16:27
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
Comment thread seps/0000-dpop-extension.md Outdated
@PieterKas

Copy link
Copy Markdown
Contributor Author

Thanks for the feedbacck @PederHP

Is the intent to sign the entire payload? There was some discussion at one point about only signing part of the payload, which I think is a very bad idea. Also, my understanding of DPoP might be flawed, but this only prevents replay attacks for idempotent requests, right? One could replay an intercepted, signed, message and thus perform a tool call with the same payload?

Under what conditions do you foresee an adversary being able to intercept an access token and a DPoP proof (e.g. for remote MCP servers the MCP client/server traffic is expected to be protected by TLS)?

This proposal uses DPoP as defined in RFC 9449 to maximize compatibility with existing infrastructure and speed deployment. DPoP sender-constrains access tokens so that only the client that obtained a token can use it. If an attacker steals an access token, for example from an MCP server log, they still cannot use it without also being able to generate a valid DPoP proof.

Even if a proof is exposed alongside the token, DPoP proofs are short-lived, which greatly limits replay risk. Deployments that need stronger replay protection can require a fresh proof via the nonce mechanism described in the PR. This can be implemented statelessly and provides a per-request proof without the overhead or retooling of existing infrastructure of signing full messages. Depending on deployment needs, fresh proofs can be required for every call or only when triggered by risk-based policy.

I would also suggest not using the verbiage "Accessing MCP server resources". This is a very HTTP-ish way to put it and may cause confusion as an MCP resource is something very specific and unrelated to this SEP. Changing this to reference "MCP requests" instead would be good, I think.

Thanks for pointing that out, please feel free to suggest alternative text.

@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 14 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 14 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

@dsp-ant dsp-ant added the roadmap/security Roadmap (horizon): Security & Authorization label Apr 15, 2026
@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 14 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

@localden localden moved this from In Review to Draft in SEP Review Pipeline Apr 28, 2026
@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 14 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

1 similar comment
@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 14 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 14 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

@nickcoai

nickcoai commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Hey @PieterKas looking into this, would you mind adding an optional definition for body-signing for stateless cases that aren't willing to accept time window based replay prevention? ala the earlier suggestion

My proposal would OAuth Protected Resource Metadata can be extended to claim dpop support and also potentially body-signing as a requirement. If absent it can default to the RFC behaviour with no extra cost. In a nutshell offering flexibility.

The use-case is essentially for a multiplexing gateway that is untrusted itself and may permit replay attacks- a client could "trust" this gateway if the onwards MCP required & enforced dpop. Timing is insufficient as the gateway by definition is on the request flow so can seamlessly modify contents.

@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 14 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

@PieterKas

Copy link
Copy Markdown
Contributor Author

The use-case is essentially for a multiplexing gateway that is untrusted itself and may permit replay attacks- a client could "trust" this gateway if the onwards MCP required & enforced dpop. Timing is insufficient as the gateway by definition is on the request flow so can seamlessly modify contents.

@nickcoai - I am not sure I follow your use case. The usage of DPoP in this SEP is constrained to the interaction between the MCP Client, OAuth Authorization Server for the MCP Server and the MCP Server. DPoP constrains the token to the MCP server it is accessing. A DPoP constrained token should not be forwarded to another MCP server and if it does, the receiving MCP server should not accept it since the original token was not intended for it. If the MCP client does not trust the MCP server, but it does trust another MCP server, it should obtain a DPoP constrained token for the MCP server it trusts and use that token. Can you clarify more about the reasons for deploying an untrusted MCP server as a middleman between MCP Clients and trusted MCP servers, and why the MCP client would not request an access token for the MCP server it actually trusts in this flow?

Made updates reflecting feedback in comments.
@localden

Copy link
Copy Markdown
Contributor

I want to revisit this and see what it would take to make this an official auth extension, similar to what we've done with client credentials.

@pcarleton thoughts?

@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 20 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

1 similar comment
@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 20 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 20 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

@oxcabe

oxcabe commented Aug 22, 2026 •

Copy link
Copy Markdown

Hi, I'm currently reviewing this SEP (including the dpop-extension draft) and the modelcontextprotocol/conformance#395, modelcontextprotocol/conformance#396 PRs. So far it's looking solid, although the conformance suite seems to be ahead of the spec. What I've found so far in terms of inconsistencies is:

There might be more inconsistencies, and since I don't have access to the https://ant-mcp-oss.slack.com Slack I'm not sure if any of these have already been discussed in there. In any case, I hope this helps 🙂


[RFC 9449 Section 11.1](https://www.rfc-editor.org/rfc/rfc9449.html#name-dpop-proof-replay) provides specific guidance on replay protection mechanisms that adress the risks of a DPoP Proofs being replayed.

MCP servers that is not capable of keeping state or perform global `jti` tracking provides DPoP proof replay protection by enforcing short `iat` acceptance windows of +/- 5 minutes and standard RFC 9449 claim validation. A stateless MCP server may provide additional replay protection by using a server supplied nonce as defined in [RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449) (e.g. by using an encrypted timestamp as the nonce value which can be decrypted, parsed and verified to be within an acceptable time window when returned in DPoP Proof) (e.g. by encrypting a timestamp using an Authenticated Encryption with Associated Data (AEAD) scheme which can be decrypted, parsed and verified to be within an acceptable time window when returned in DPoP Proof).

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.

If the nonce is implemented as an encrypted timestamp then that same nonce value will be valid for all clients that interact with a MCP server over a given time period. I can't immediately think of an attack that multi-client nonces would help enable:

  • Pre-generation is still impossible for the client since it cannot perform encryption of the nonce
  • Replay protection is unaffected - the nonce affects the server-accepted lifetime of the DPoP proof, not its ability to statefully track replay

Nonetheless, it strikes me as odd for the nonce used in sender-constraining tokens to clients to not itself be constrained to a client. Is this a problem worth solving? Am I overthinking it? One solution - a server could also encode the client ID in the nonce as well - ENC(CONCAT($client_id, "|",$timestamp)) - to create a unique nonce per client per time period.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thank @max-stytch - It would be good to understand the threat you have in mind (designing countermeasures without defining the threat invites complexity without clear benefits).

To my knowledge this is not something that has come up for OAuth in general, which makes me hesitate on whether this is worth solving. Is there something about how MCP uses OAuth that would create a risk here?

Your idea is a clever way to make timestamped nonces unique and specific to a client when interacting with the Authorization Server. I don't believe the Resource Server in OAuth typically has knowledge of the client_id though. However, if timestamps are not sufficiently unique, it could be salted or additional information could be added (e.g. a session identifier if it exists etc) if a deployment needed it.

In terms of the specification, how the nonce is construsted is not an interoperability issue (only the server needs to know how to handle the nonce when it receives it back), so we can provide guidance, while still leaving implementers with options on how they implement the nonce.


[RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449) already provides the core security properties for sender constraining OAuth Access Tokens. When combined with TLS transport-layer security and appropriate token and proof lifetimes, these mechanisms are sufficient to significantly reduce the risks associated with token exfiltration and replay in MCP deployments, even if the MCP server is not capable of maintaining global state.

## Backward 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.

I would appreciate a section explaining how MCP Servers and Client should work with WWW-Authenticate headers, for both DPoP + DPoP/Bearer backwards compatibility situations. 9449 describes the scheme but MCP makes heavy use of WWW headers for scope negotiation, and there are many existing client libraries that probably won't play well with MCP servers accepting both token types. I assume a header would look something like the following?

POST /mcp HTTP/1.1
Host: mcp.example.com

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer, DPoP algs="ES256 PS256",
    resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource",
    scope="files:read"

Showing how scope negotiation + PRM + DPoP upgrades work together in one place would be very helpful.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks @max-stytch - to what extent can we just rely on the PRM doc to advertise whether DPoP is required (or not) and what algorithms it supports rather than having a negotiation via headers? RFC 9728 already specifies both dpop_signing_alg_values_supported and dpop_bound_access_tokens_required (which we should make mandatory in this SEP)?

Is the case your thinking of specifically when a MCP server supports both DPoP and Bearer, and the client only supports one or the other?

@sep-automation-bot

Copy link
Copy Markdown

Maintainer Activity Check

Hi @D-McAdams!

You're assigned to this SEP but there hasn't been any activity from you in 20 days.

Please provide an update on:

  • Current status of your review/work
  • Any blockers or concerns
  • Expected timeline for next steps

If you're no longer able to sponsor this SEP, please let us know so we can find another maintainer.


This is an automated message from the SEP lifecycle bot.

@PieterKas

Copy link
Copy Markdown
Contributor Author

@oxcabe - thanks for your review - you are correct, the two documents have drifted and needs to be reconciled. Thanks for pointing to specific gaps. Much appreciated.

This branch has not been deployed

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

Labels

auth draft SEP proposal with a sponsor. extension roadmap/security Roadmap (horizon): Security & Authorization security SEP

Projects

Status: Draft

Development

Successfully merging this pull request may close these issues.

10 participants