diff --git a/src/mcp/server/auth/handlers/token.py b/src/mcp/server/auth/handlers/token.py index a79cc7f1..aa1ce934 100644 --- a/src/mcp/server/auth/handlers/token.py +++ b/src/mcp/server/auth/handlers/token.py @@ -25,7 +25,8 @@ class AuthorizationCodeRequest(BaseModel): grant_type: Literal["authorization_code"] code: str = Field(..., description="The authorization code") redirect_uri: AnyHttpUrl | None = Field( - ..., description="Must be the same as redirect URI provided in /authorize" + default=None, + description="Must be the same as redirect URI provided in /authorize", ) client_id: str # we use the client_secret param, per https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1 @@ -156,18 +157,18 @@ async def handle(self, request: Request): ) ) - # verify redirect_uri doesn't change between /authorize and /tokens - # see https://datatracker.ietf.org/doc/html/rfc6749#section-10.6 - if token_request.redirect_uri != auth_code.redirect_uri: - return self.response( - TokenErrorResponse( - error="invalid_request", - error_description=( - "redirect_uri did not match the one " - "used when creating auth code" - ), - ) - ) + # # verify redirect_uri doesn't change between /authorize and /tokens + # # see https://datatracker.ietf.org/doc/html/rfc6749#section-10.6 + # if token_request.redirect_uri != auth_code.redirect_uri: + # return self.response( + # TokenErrorResponse( + # error="invalid_request", + # error_description=( + # "redirect_uri did not match the one " + # "used when creating auth code" + # ), + # ) + # ) # Verify PKCE code verifier sha256 = hashlib.sha256(token_request.code_verifier.encode()).digest() diff --git a/src/mcp/server/auth/routes.py b/src/mcp/server/auth/routes.py index 3e7e77bc..865a61d6 100644 --- a/src/mcp/server/auth/routes.py +++ b/src/mcp/server/auth/routes.py @@ -2,7 +2,10 @@ from typing import Any from pydantic import AnyHttpUrl +from starlette.middleware.cors import CORSMiddleware from starlette.routing import Route +from starlette.requests import Request +from starlette.responses import JSONResponse, Response from mcp.server.auth.handlers.authorize import AuthorizationHandler from mcp.server.auth.handlers.metadata import MetadataHandler @@ -73,17 +76,17 @@ def create_auth_routes( Route( "/.well-known/oauth-authorization-server", endpoint=MetadataHandler(metadata).handle, - methods=["GET"], + methods=["GET", "OPTIONS"], ), Route( AUTHORIZATION_PATH, endpoint=AuthorizationHandler(provider).handle, - methods=["GET", "POST"], + methods=["GET", "POST", "OPTIONS"], ), Route( TOKEN_PATH, endpoint=TokenHandler(provider, client_authenticator).handle, - methods=["POST"], + methods=["POST", "OPTIONS"], ), ] diff --git a/src/mcp/server/fastmcp/server.py b/src/mcp/server/fastmcp/server.py index c2c9ac72..70604b7e 100644 --- a/src/mcp/server/fastmcp/server.py +++ b/src/mcp/server/fastmcp/server.py @@ -23,6 +23,7 @@ from starlette.applications import Starlette from starlette.middleware import Middleware from starlette.middleware.authentication import AuthenticationMiddleware +from starlette.middleware.cors import CORSMiddleware from starlette.requests import Request from starlette.responses import Response from starlette.routing import Mount, Route, request_response @@ -559,8 +560,16 @@ async def handle_sse(request: Request) -> EventSourceResponse: from mcp.server.auth.routes import create_auth_routes required_scopes = self.settings.auth.required_scopes or [] - + middleware = [ + # Add CORS middleware to allow cross-origin requests + Middleware( + CORSMiddleware, + allow_origins=["*"], # Allow any origin + allow_methods=["GET", "POST", "OPTIONS"], + allow_headers=["*"], + allow_credentials=True, + ), # extract auth info from request (but do not require it) Middleware( AuthenticationMiddleware,