[BUG] DPoP is not used for a pre-registered MCP OAuth client
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When connecting Claude Code to a remote MCP server using OAuth with a pre-registered client, the Authorization Server requires DPoP-bound access tokens according to RFC 9449.
https://www.rfc-editor.org/info/rfc9449/
https://github.com/modelcontextprotocol/typescript-sdk/blob/60321700871029401a2e3bed8fdf4f02c9ec3331/.changeset/dpop-client-tokens.md?plain=1#L10
The Authorization Server advertises DPoP support in its metadata:
{
"dpop_signing_alg_values_supported": ["ES256"]
}
The pre-registered OAuth client is configured on the Authorization Server to require DPoP-bound access tokens (dpop_bound_access_tokens = true).
However, Claude Code performs the token request without a DPoP proof.
Actual behavior
For a pre-registered MCP OAuth client, I cannot find a way to enable DPoP.
The Authorization Server advertises:
{
"dpop_signing_alg_values_supported": ["ES256"]
}
but the initial /token request from Claude Code does not contain:
DPoP: <proof JWT>
As a result, an Authorization Server that enforces DPoP for this client_id must reject the token request.
MCP configuration
The MCP server uses a pre-registered OAuth client, approximately:
{
"type": "http",
"url": "https://mcp.example.com/mcp",
"oauth": {
"clientId": "<pre-registered-client-id>",
"clientSecret": "<client-secret>"
}
}
There does not appear to be an option such as:
{
"oauth": {
"clientId": "...",
"clientSecret": "...",
"dpop": true
}
}
What Should Happen?
Claude Code should provide a way to enable DPoP for a pre-registered MCP OAuth client.
When DPoP is enabled, the authorization-code token request should contain a DPoP proof:
POST /token
DPoP: <proof JWT>
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=...&
client_id=...&
code_verifier=...
The resulting DPoP-bound access token should then be used for MCP requests as:
Authorization: DPoP <access_token>
DPoP: <proof JWT>
Error Messages/Logs
Steps to Reproduce
- Configure a remote HTTP MCP server requiring OAuth.
- Configure Claude Code to use a pre-registered
client_id. - Configure the Authorization Server to require DPoP-bound access tokens for that client.
- Publish DPoP support in the Authorization Server metadata:
{
"dpop_signing_alg_values_supported": ["ES256"]
}
- Start the OAuth flow from Claude Code.
- Observe the request to the token endpoint.
The request does not contain a DPoP header, so the Authorization Server rejects it because the pre-registered client requires DPoP.
Claude Model
Not sure / Multiple models
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.204
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
The MCP TypeScript SDK has DPoP support through OAuthClientProvider.dpop() / DpopSession.
It is unclear whether Claude Code currently wires this capability into its MCP OAuth provider, particularly for pre-registered clients.
If DPoP is intentionally opt-in rather than automatically enabled based on dpop_signing_alg_values_supported, it would be useful to expose a Claude Code MCP configuration option for enabling it, for example:
{
"oauth": {
"clientId": "...",
"clientSecret": "...",
"dpop": true
}
}
This would allow Claude Code to interoperate with Authorization Servers that require sender-constrained access tokens using RFC 9449.