|
9 | 9 | from starlette.responses import RedirectResponse, Response |
10 | 10 |
|
11 | 11 | from mcp.server.auth.errors import ( |
12 | | - InvalidRequestError, |
13 | 12 | OAuthError, |
14 | 13 | stringify_pydantic_error, |
15 | 14 | ) |
|
19 | 18 | OAuthServerProvider, |
20 | 19 | construct_redirect_uri, |
21 | 20 | ) |
22 | | -from mcp.shared.auth import OAuthClientInformationFull |
| 21 | +from mcp.shared.auth import ( |
| 22 | + InvalidRedirectUriError, |
| 23 | + InvalidScopeError, |
| 24 | +) |
23 | 25 |
|
24 | 26 | logger = logging.getLogger(__name__) |
25 | 27 |
|
@@ -66,37 +68,6 @@ class AuthorizationErrorResponse(BaseModel): |
66 | 68 | state: str | None = None |
67 | 69 |
|
68 | 70 |
|
69 | | -def validate_scope( |
70 | | - requested_scope: str | None, client: OAuthClientInformationFull |
71 | | -) -> list[str] | None: |
72 | | - if requested_scope is None: |
73 | | - return None |
74 | | - requested_scopes = requested_scope.split(" ") |
75 | | - allowed_scopes = [] if client.scope is None else client.scope.split(" ") |
76 | | - for scope in requested_scopes: |
77 | | - if scope not in allowed_scopes: |
78 | | - raise InvalidRequestError(f"Client was not registered with scope {scope}") |
79 | | - return requested_scopes |
80 | | - |
81 | | - |
82 | | -def validate_redirect_uri( |
83 | | - redirect_uri: AnyHttpUrl | None, client: OAuthClientInformationFull |
84 | | -) -> AnyHttpUrl: |
85 | | - if redirect_uri is not None: |
86 | | - # Validate redirect_uri against client's registered redirect URIs |
87 | | - if redirect_uri not in client.redirect_uris: |
88 | | - raise InvalidRequestError( |
89 | | - f"Redirect URI '{redirect_uri}' not registered for client" |
90 | | - ) |
91 | | - return redirect_uri |
92 | | - elif len(client.redirect_uris) == 1: |
93 | | - return client.redirect_uris[0] |
94 | | - else: |
95 | | - raise InvalidRequestError( |
96 | | - "redirect_uri must be specified when client has multiple registered URIs" |
97 | | - ) |
98 | | - |
99 | | - |
100 | 71 | def best_effort_extract_string( |
101 | 72 | key: str, params: None | FormData | QueryParams |
102 | 73 | ) -> str | None: |
@@ -146,8 +117,8 @@ async def error_response( |
146 | 117 | best_effort_extract_string("redirect_uri", params) |
147 | 118 | ).root |
148 | 119 | try: |
149 | | - redirect_uri = validate_redirect_uri(raw_redirect_uri, client) |
150 | | - except (ValidationError, InvalidRequestError): |
| 120 | + redirect_uri = client.validate_redirect_uri(raw_redirect_uri) |
| 121 | + except (ValidationError, InvalidRedirectUriError): |
151 | 122 | pass |
152 | 123 | if state is None: |
153 | 124 | # make last-ditch effort to load state |
@@ -213,22 +184,22 @@ async def error_response( |
213 | 184 |
|
214 | 185 | # Validate redirect_uri against client's registered URIs |
215 | 186 | try: |
216 | | - redirect_uri = validate_redirect_uri(auth_request.redirect_uri, client) |
217 | | - except InvalidRequestError as validation_error: |
| 187 | + redirect_uri = client.validate_redirect_uri(auth_request.redirect_uri) |
| 188 | + except InvalidRedirectUriError as validation_error: |
218 | 189 | # For redirect_uri validation errors, return direct error (no redirect) |
219 | 190 | return await error_response( |
220 | 191 | error="invalid_request", |
221 | | - error_description=validation_error.error_description, |
| 192 | + error_description=validation_error.message, |
222 | 193 | ) |
223 | 194 |
|
224 | 195 | # Validate scope - for scope errors, we can redirect |
225 | 196 | try: |
226 | | - scopes = validate_scope(auth_request.scope, client) |
227 | | - except InvalidRequestError as validation_error: |
| 197 | + scopes = client.validate_scope(auth_request.scope) |
| 198 | + except InvalidScopeError as validation_error: |
228 | 199 | # For scope errors, redirect with error parameters |
229 | 200 | return await error_response( |
230 | 201 | error="invalid_scope", |
231 | | - error_description=validation_error.error_description, |
| 202 | + error_description=validation_error.message, |
232 | 203 | ) |
233 | 204 |
|
234 | 205 | # Setup authorization parameters |
|
0 commit comments