Skip to content

Conversation

jlowin
Copy link
Owner

@jlowin jlowin commented Oct 10, 2025

FastMCP's OAuth proxy uses a static client ID when forwarding authorization requests to upstream providers. This creates a confused deputy vulnerability: an attacker can register a malicious client via the open DCR endpoint, then trick a victim into authorizing it. Because the victim already has a consent cookie for the static client ID, the upstream authorization server bypasses the consent screen and issues an authorization code that redirects to the attacker's server.

This PR implements the mitigation required by the MCP specification: the proxy now obtains explicit user consent for each dynamically registered client before forwarding to the upstream authorization server. It also updates relevant documentation.

image

The consent flow:

  • User initiates authorization → redirected to /consent endpoint
  • Consent page displays client details and requested scopes with CSRF protection
  • User approves/denies → decision stored in signed cookie
  • On approval, user is forwarded to upstream authorization server
  • Subsequent requests from the same client auto-approve via signed cookie

Server-side storage ensures OAuth transactions and authorization codes persist across requests, with full support for custom storage backends via `AsyncKeyValue`.

Thanks to @localden for identifying this vulnerability and providing detailed analysis on this topic in his blog post.

Implements user consent requirement before OAuth authorization completes, protecting against confused deputy attacks per MCP security best practices. When a new or unrecognized MCP client attempts authorization, users see a consent page showing client details, redirect URI, and requested scopes before approving.

Key features:
- Consent page with client details and scope display
- CSRF-protected approval/denial with cryptographically signed cookies
- Storage-backed transaction management for server restarts
- Responsive UI with security tooltip explaining protection
- Auto-approval for previously consented clients

Creates shared UI utilities module (src/fastmcp/utilities/ui.py) with reusable HTML/CSS components for OAuth pages, consent flows, and future user-facing interfaces.
@marvin-context-protocol marvin-context-protocol bot added bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. high-priority auth Related to authentication (Bearer, JWT, OAuth, WorkOS) for client or server. labels Oct 10, 2025
@jlowin jlowin added this to the 2.13.0 milestone Oct 10, 2025
@jlowin
Copy link
Owner Author

jlowin commented Oct 10, 2025

@strawgate this is a great test case for the new OAuth storage mechanisms

# Need to allow form-action for form submission
csp_policy = "default-src 'none'; style-src 'unsafe-inline'; img-src https:; base-uri 'none'; form-action *"

return create_page(

Choose a reason for hiding this comment

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

Super excited to see this and with remote storage for all state! Sorry if I am commenting too early but would be great if the consent page could be customizable to show more of the brand of the MCP server, and the very least, be able to replace "FastMCP" with the server name and the logo. Or maybe just be able to pass in an entire custom HTML - Thanks!

Copy link
Owner Author

Choose a reason for hiding this comment

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

Agree! At the moment auth modules don't receive the server (other way around) so I punted on e.g. server name for this draft because it required more changes than I wanted in this PR

@strawgate
Copy link
Collaborator

Generated Image October 10, 2025 - 10_23PM (1)

@jlowin
Copy link
Owner Author

jlowin commented Oct 11, 2025

Feeling good about the state of this and want to continue iterating on some token storage concerns without polluting it so I'm going to merge this as we continue pressing on state / storage for sensitive items.

@jlowin jlowin merged commit 7b7e277 into main Oct 11, 2025
15 checks passed
@jlowin jlowin deleted the consent branch October 11, 2025 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auth Related to authentication (Bearer, JWT, OAuth, WorkOS) for client or server. bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants