Skip to content

Commit 6d24518

Browse files
committed
Remove ClientAuthRequest
1 parent dfcba82 commit 6d24518

File tree

3 files changed

+20
-45
lines changed

3 files changed

+20
-45
lines changed

src/mcp/server/auth/handlers/token.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,33 @@
1515
from mcp.server.auth.json_response import PydanticJSONResponse
1616
from mcp.server.auth.middleware.client_auth import (
1717
ClientAuthenticator,
18-
ClientAuthRequest,
1918
)
2019
from mcp.server.auth.provider import OAuthServerProvider
2120
from mcp.shared.auth import OAuthToken
2221

2322

24-
class AuthorizationCodeRequest(ClientAuthRequest):
23+
class AuthorizationCodeRequest(BaseModel):
2524
# See https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3
2625
grant_type: Literal["authorization_code"]
2726
code: str = Field(..., description="The authorization code")
2827
redirect_uri: AnyHttpUrl | None = Field(
2928
..., description="Must be the same as redirect URI provided in /authorize"
3029
)
3130
client_id: str
31+
# we use the client_secret param, per https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1
32+
client_secret: str | None = None
3233
# See https://datatracker.ietf.org/doc/html/rfc7636#section-4.5
3334
code_verifier: str = Field(..., description="PKCE code verifier")
3435

3536

36-
class RefreshTokenRequest(ClientAuthRequest):
37+
class RefreshTokenRequest(BaseModel):
3738
# See https://datatracker.ietf.org/doc/html/rfc6749#section-6
3839
grant_type: Literal["refresh_token"]
3940
refresh_token: str = Field(..., description="The refresh token")
4041
scope: str | None = Field(None, description="Optional scope parameter")
42+
client_id: str
43+
# we use the client_secret param, per https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1
44+
client_secret: str | None = None
4145

4246

4347
class TokenRequest(RootModel):
@@ -103,7 +107,10 @@ async def handle(self, request: Request):
103107
)
104108

105109
try:
106-
client_info = await self.client_authenticator(token_request)
110+
client_info = await self.client_authenticator.authenticate(
111+
client_id=token_request.client_id,
112+
client_secret=token_request.client_secret,
113+
)
107114
except InvalidClientError as e:
108115
return self.response(e.error_response())
109116

src/mcp/server/auth/middleware/client_auth.py

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,16 @@
11
import time
22

3-
from pydantic import BaseModel
4-
53
from mcp.server.auth.errors import InvalidClientError
64
from mcp.server.auth.provider import OAuthRegisteredClientsStore
75
from mcp.shared.auth import OAuthClientInformationFull
86

97

10-
class ClientAuthRequest(BaseModel):
11-
# TODO: mix this directly into TokenRequest
12-
13-
client_id: str
14-
client_secret: str | None = None
15-
16-
178
class ClientAuthenticator:
189
"""
1910
ClientAuthenticator is a callable which validates requests from a client
20-
application,
21-
used to verify /token and /revoke calls.
11+
application, used to verify /token calls.
2212
If, during registration, the client requested to be issued a secret, the
23-
authenticator asserts that /token and /register calls must be authenticated with
13+
authenticator asserts that /token calls must be authenticated with
2414
that same token.
2515
NOTE: clients can opt for no authentication during registration, in which case this
2616
logic is skipped.
@@ -35,19 +25,21 @@ def __init__(self, clients_store: OAuthRegisteredClientsStore):
3525
"""
3626
self.clients_store = clients_store
3727

38-
async def __call__(self, request: ClientAuthRequest) -> OAuthClientInformationFull:
28+
async def authenticate(
29+
self, client_id: str, client_secret: str | None
30+
) -> OAuthClientInformationFull:
3931
# Look up client information
40-
client = await self.clients_store.get_client(request.client_id)
32+
client = await self.clients_store.get_client(client_id)
4133
if not client:
4234
raise InvalidClientError("Invalid client_id")
4335

4436
# If client from the store expects a secret, validate that the request provides
4537
# that secret
4638
if client.client_secret:
47-
if not request.client_secret:
39+
if not client_secret:
4840
raise InvalidClientError("Client secret is required")
4941

50-
if client.client_secret != request.client_secret:
42+
if client.client_secret != client_secret:
5143
raise InvalidClientError("Invalid client_secret")
5244

5345
if (

src/mcp/server/auth/provider.py

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
"""
2-
OAuth server provider interfaces for MCP authorization.
3-
4-
Corresponds to TypeScript file: src/server/auth/provider.ts
5-
"""
6-
71
from typing import Literal, Protocol
82
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
93

@@ -17,12 +11,6 @@
1711

1812

1913
class AuthorizationParams(BaseModel):
20-
"""
21-
Parameters for the authorization flow.
22-
23-
Corresponds to AuthorizationParams in src/server/auth/provider.ts
24-
"""
25-
2614
state: str | None = None
2715
scopes: list[str] | None = None
2816
code_challenge: str
@@ -46,12 +34,6 @@ class RefreshToken(BaseModel):
4634

4735

4836
class OAuthRegisteredClientsStore(Protocol):
49-
"""
50-
Interface for storing and retrieving registered OAuth clients.
51-
52-
Corresponds to OAuthRegisteredClientsStore in src/server/auth/clients.ts
53-
"""
54-
5537
async def get_client(self, client_id: str) -> OAuthClientInformationFull | None:
5638
"""
5739
Retrieves client information by client ID.
@@ -66,7 +48,7 @@ async def get_client(self, client_id: str) -> OAuthClientInformationFull | None:
6648

6749
async def register_client(self, client_info: OAuthClientInformationFull) -> None:
6850
"""
69-
Registers a new client
51+
Saves client information as part of registering it.
7052
7153
Args:
7254
client_info: The client metadata to register.
@@ -75,12 +57,6 @@ async def register_client(self, client_info: OAuthClientInformationFull) -> None
7557

7658

7759
class OAuthServerProvider(Protocol):
78-
"""
79-
Implements an end-to-end OAuth server.
80-
81-
Corresponds to OAuthServerProvider in src/server/auth/provider.ts
82-
"""
83-
8460
@property
8561
def clients_store(self) -> OAuthRegisteredClientsStore:
8662
"""

0 commit comments

Comments
 (0)