@@ -82,6 +82,10 @@ def get_auth_provider(cfg: ClientContext, http_client):
8282PYSQL_OAUTH_AZURE_CLIENT_ID = "96eecda7-19ea-49cc-abb5-240097d554f5"
8383PYSQL_OAUTH_REDIRECT_PORT_RANGE = list (range (8020 , 8025 ))
8484PYSQL_OAUTH_AZURE_REDIRECT_PORT_RANGE = [8030 ]
85+ # Base (app-neutral) redirect port used when a caller supplies their OWN
86+ # oauth_client_id but no redirect port: the driver must NOT pin its own
87+ # app-specific default range in that case (see AUTH-013 / PECOBLR-4039).
88+ PYSQL_OAUTH_BASE_REDIRECT_PORT_RANGE = [8030 ]
8589
8690
8791def normalize_host_name (hostname : str ):
@@ -102,7 +106,7 @@ def get_python_sql_connector_auth_provider(hostname: str, http_client, **kwargs)
102106 # TODO : unify all the auth mechanisms with the Python SDK
103107
104108 auth_type = kwargs .get ("auth_type" )
105- client_id , redirect_port_range = get_client_id_and_redirect_port (
109+ default_client_id , default_redirect_port_range = get_client_id_and_redirect_port (
106110 auth_type == AuthType .AZURE_OAUTH .value
107111 )
108112
@@ -112,23 +116,44 @@ def get_python_sql_connector_auth_provider(hostname: str, http_client, **kwargs)
112116 "Please use OAuth or access token instead."
113117 )
114118
119+ # A caller who supplies their OWN oauth_client_id owns the rest of the U2M
120+ # bundle: the driver forwards their scopes and redirect port verbatim and must
121+ # NOT substitute its own app-specific defaults (see AUTH-013 / PECOBLR-4039).
122+ # Only when the caller relies on the driver's default client_id do the
123+ # driver's app-specific default scopes/port range apply.
124+ caller_client_id = kwargs .get ("oauth_client_id" )
125+ oauth_redirect_port = kwargs .get ("oauth_redirect_port" )
126+ oauth_scopes = kwargs .get ("oauth_scopes" )
127+
128+ scopes = oauth_scopes or PYSQL_OAUTH_SCOPES
129+ if caller_client_id :
130+ client_id = caller_client_id
131+ # Foreign client_id with no explicit port falls through to the base
132+ # (app-neutral) default, NOT the driver's app-specific range.
133+ redirect_port_range = (
134+ [oauth_redirect_port ]
135+ if oauth_redirect_port
136+ else PYSQL_OAUTH_BASE_REDIRECT_PORT_RANGE
137+ )
138+ else :
139+ client_id = default_client_id
140+ redirect_port_range = (
141+ [oauth_redirect_port ] if oauth_redirect_port else default_redirect_port_range
142+ )
143+
115144 cfg = ClientContext (
116145 hostname = normalize_host_name (hostname ),
117146 auth_type = auth_type ,
118147 access_token = kwargs .get ("access_token" ),
119148 use_cert_as_auth = kwargs .get ("_use_cert_as_auth" ),
120149 tls_client_cert_file = kwargs .get ("_tls_client_cert_file" ),
121- oauth_scopes = PYSQL_OAUTH_SCOPES ,
122- oauth_client_id = kwargs . get ( "oauth_client_id" ) or client_id ,
150+ oauth_scopes = scopes ,
151+ oauth_client_id = client_id ,
123152 azure_client_id = kwargs .get ("azure_client_id" ),
124153 azure_client_secret = kwargs .get ("azure_client_secret" ),
125154 azure_tenant_id = kwargs .get ("azure_tenant_id" ),
126155 azure_workspace_resource_id = kwargs .get ("azure_workspace_resource_id" ),
127- oauth_redirect_port_range = (
128- [kwargs ["oauth_redirect_port" ]]
129- if kwargs .get ("oauth_client_id" ) and kwargs .get ("oauth_redirect_port" )
130- else redirect_port_range
131- ),
156+ oauth_redirect_port_range = redirect_port_range ,
132157 oauth_persistence = kwargs .get ("experimental_oauth_persistence" ),
133158 credentials_provider = kwargs .get ("credentials_provider" ),
134159 identity_federation_client_id = kwargs .get ("identity_federation_client_id" ),
0 commit comments