Skip to content

RevocationRequest requires client_secret, so public clients get 400 from /revoke #3648

Description

@k-sok

Summary

POST /revoke answers 400 invalid_request to a public client (token_endpoint_auth_method: none) that sends only token and client_id, which is what RFC 7009 allows for a client without credentials.

Cause

In mcp/server/auth/handlers/revoke.py the form model is

class RevocationRequest(BaseModel):
    token: str
    token_type_hint: Literal["access_token", "refresh_token"] | None = None
    client_id: str
    client_secret: str | None

client_secret: str | None has no default, so pydantic treats the field as required (nullable, but it must be present). A public client omits it, RevocationRequest.model_validate(dict(form_data)) fails and the handler returns 400 before the provider's revoke_token is called. ClientAuthenticator already handles the secret on its own (it reads it from the form or the Basic header and demands it only for a client registered with one), so the model does not need the field at all, or it needs = None.

Reproduction

Register a client with token_endpoint_auth_method: "none", obtain tokens, then POST /revoke with token=<refresh token>&client_id=<id>. Expected 200, actual 400 {"error": "invalid_request", ...}. Claude Code registers this way and hit it (mcp 2.2.0).

Suggested fix

client_secret: str | None = None (or drop the field).

Activity

  1. added
    v2Affects the v2 line (2.x on main)
    v1Affects the v1.x maintenance line
    on Oct 6, 2026
  2. maxisbey commented on Oct 6, 2026

    @maxisbey
    Contributor

    Thanks for the clear report. This is the same problem as #3508, so I'm going to close this one as a duplicate to keep everything in one place.

    Your diagnosis matches what's there: the field has no default, so a public client that leaves it out is rejected before the provider is called. It's also useful to know you hit this through Claude Code on 2.2.0, since that's what helps us prioritise it. Feel free to add anything else on #3508 :)

    AI Disclaimer


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    v1Affects the v1.x maintenance linev2Affects the v2 line (2.x on main)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions