@@ -341,6 +341,41 @@ async def test_scope_is_selected_from_the_www_authenticate_challenge_over_prm_me
341341 assert json .loads (register .content )["scope" ] == "from-header"
342342
343343
344+ async def test_authorization_endpoint_existing_query_params_are_preserved () -> None :
345+ """Authorization metadata endpoints may include provider-required query params."""
346+ provider = InMemoryAuthorizationServerProvider ()
347+ server = Server ("guarded" , on_list_tools = list_tools )
348+ override = OAuthMetadata (
349+ issuer = AnyHttpUrl (f"{ BASE_URL } /" ),
350+ authorization_endpoint = AnyHttpUrl (f"{ BASE_URL } /authorize?prompt=select_account" ),
351+ token_endpoint = AnyHttpUrl (f"{ BASE_URL } /token" ),
352+ registration_endpoint = AnyHttpUrl (f"{ BASE_URL } /register" ),
353+ scopes_supported = ["mcp" ],
354+ grant_types_supported = ["authorization_code" , "refresh_token" ],
355+ code_challenge_methods_supported = ["S256" ],
356+ )
357+ serve = {ASM_PATH : override .model_dump_json (exclude_none = True ).encode ()}
358+
359+ with anyio .fail_after (5 ):
360+ async with connect_with_oauth (
361+ server ,
362+ provider = provider ,
363+ app_shim = lambda app : shimmed_app (app , serve = serve ),
364+ ) as (client , headless ):
365+ await client .list_tools ()
366+
367+ assert headless .authorize_url is not None
368+ split_url = urlsplit (headless .authorize_url )
369+ assert split_url .path == "/authorize"
370+ assert split_url .query .count ("?" ) == 0
371+
372+ params = authorize_params (headless .authorize_url )
373+ assert params ["prompt" ] == "select_account"
374+ assert params ["response_type" ] == "code"
375+ assert params ["client_id" ] != ""
376+ assert params ["redirect_uri" ] == REDIRECT_URI
377+
378+
344379@requirement ("client-auth:pkce:refuse-if-unsupported" )
345380async def test_pkce_is_still_sent_when_as_metadata_omits_code_challenge_methods_supported () -> None :
346381 """AS metadata without `code_challenge_methods_supported` does not stop the client sending PKCE.
0 commit comments