1111from mcp .types import Tool as MCPLibTool
1212from pydantic import AnyUrl , BaseModel , Field , model_validator
1313
14+ from onyx .auth .oauth_token_manager import conflicting_authorization_params
1415from onyx .db .enums import (
1516 EndpointPolicy ,
1617 MCPAuthenticationPerformer ,
1920 MCPServerStatus ,
2021 MCPTransport ,
2122)
23+ from onyx .oauth .models import (
24+ OAuthConfigurationFingerprint ,
25+ PKCECodeVerifier ,
26+ SafeOAuthReturnPath ,
27+ )
2228
2329# Matches `{placeholder_name}` inside header value templates.
2430_PLACEHOLDER_RE = re .compile (r"\{([^}]+)\}" )
2531# RFC 9110 field-name syntax: a non-empty sequence of HTTP token characters.
2632_HTTP_FIELD_NAME_RE = re .compile (r"[!#$%&'*+\-.^_`|~0-9A-Za-z]+" )
27- RESERVED_MCP_OAUTH_AUTHORIZATION_PARAMS = {
28- "client_id" ,
29- "code_challenge" ,
30- "code_challenge_method" ,
31- "redirect_uri" ,
32- "resource" ,
33- "response_type" ,
34- "scope" ,
35- "state" ,
36- }
3733
3834
3935def _build_auto_substitution_map (* , user_email : str ) -> dict [str , str ]:
@@ -387,8 +383,8 @@ def validate_auth_configuration(self) -> "MCPToolCreateRequest":
387383 raise ValueError (
388384 "oauth_token_endpoint is required for known-provider OAuth mode"
389385 )
390- reserved_params = RESERVED_MCP_OAUTH_AUTHORIZATION_PARAMS . intersection (
391- self .oauth_additional_auth_params or {}
386+ reserved_params = conflicting_authorization_params (
387+ self .oauth_additional_auth_params
392388 )
393389 if reserved_params :
394390 raise ValueError (
@@ -511,7 +507,9 @@ class MCPOAuthConnectResponse(BaseModel):
511507
512508class MCPUserOAuthConnectRequest (BaseModel ):
513509 server_id : int = Field (..., description = "ID of the MCP server" )
514- return_path : str = Field (..., description = "Path to redirect to after callback" )
510+ return_path : SafeOAuthReturnPath = Field (
511+ ..., description = "Path to redirect to after callback"
512+ )
515513 include_resource_param : bool = Field (..., description = "Include resource parameter" )
516514 force_reauthentication : bool = Field (
517515 default = False ,
@@ -539,17 +537,6 @@ class MCPUserOAuthConnectRequest(BaseModel):
539537 ),
540538 )
541539
542- @model_validator (mode = "after" )
543- def validate_return_path (self ) -> "MCPUserOAuthConnectRequest" :
544- if (
545- not self .return_path .startswith ("/" )
546- or self .return_path .startswith ("//" )
547- or "\\ " in self .return_path
548- or any (not character .isprintable () for character in self .return_path )
549- ):
550- raise ValueError ("return_path must be a safe internal path" )
551- return self
552-
553540
554541class MCPUserOAuthConnectResponse (BaseModel ):
555542 server_id : int
@@ -574,7 +561,7 @@ def validate_outcome(self) -> "MCPUserOAuthConnectResponse":
574561class MCPPendingOAuthAuthorization (BaseModel ):
575562 authorization_url : str
576563 state : str
577- code_verifier : str
564+ code_verifier : PKCECodeVerifier
578565
579566
580567class MCPOAuthServerSnapshot (BaseModel ):
@@ -592,12 +579,12 @@ class MCPOAuthServerSnapshot(BaseModel):
592579class MCPOAuthFlowState (BaseModel ):
593580 server_id : int
594581 connection_config_id : int
595- return_path : str
596- code_verifier : str
582+ return_path : SafeOAuthReturnPath
583+ code_verifier : PKCECodeVerifier
597584 redirect_uri : AnyUrl
598585 server_snapshot : MCPOAuthServerSnapshot
599- connection_headers_fingerprint : str
600- client_information_fingerprint : str
586+ connection_headers_fingerprint : OAuthConfigurationFingerprint
587+ client_information_fingerprint : OAuthConfigurationFingerprint
601588 protected_resource_metadata : ProtectedResourceMetadata | None = None
602589 oauth_metadata : OAuthMetadata | None = None
603590 authorization_server_url : str | None = None
0 commit comments