@@ -261,6 +261,109 @@ async def test_oauth_discovery_fallback_order(self, oauth_provider):
261261            "https://api.example.com/v1/mcp/.well-known/openid-configuration" ,
262262        ]
263263
264+     @pytest .mark .anyio  
265+     async  def  test_oauth_discovery_fallback_conditions (self , oauth_provider ):
266+         """Test the conditions during which an AS metadata discovery fallback will be attempted.""" 
267+         # Ensure no tokens are stored 
268+         oauth_provider .context .current_tokens  =  None 
269+         oauth_provider .context .token_expiry_time  =  None 
270+         oauth_provider ._initialized  =  True 
271+ 
272+         # Mock client info to skip DCR 
273+         oauth_provider .context .client_info  =  OAuthClientInformationFull (
274+             client_id = "existing_client" ,
275+             redirect_uris = [AnyUrl ("http://localhost:3030/callback" )],
276+         )
277+ 
278+         # Create a test request 
279+         test_request  =  httpx .Request ("GET" , "https://api.example.com/v1/mcp" )
280+ 
281+         # Mock the auth flow 
282+         auth_flow  =  oauth_provider .async_auth_flow (test_request )
283+ 
284+         # First request should be the original request without auth header 
285+         request  =  await  auth_flow .__anext__ ()
286+         assert  "Authorization"  not  in request .headers 
287+ 
288+         # Send a 401 response to trigger the OAuth flow 
289+         response  =  httpx .Response (
290+             401 ,
291+             headers = {
292+                 "WWW-Authenticate" : 'Bearer resource_metadata="https://api.example.com/.well-known/oauth-protected-resource"' 
293+             },
294+             request = test_request ,
295+         )
296+ 
297+         # Next request should be to discover protected resource metadata 
298+         discovery_request  =  await  auth_flow .asend (response )
299+         assert  str (discovery_request .url ) ==  "https://api.example.com/.well-known/oauth-protected-resource" 
300+         assert  discovery_request .method  ==  "GET" 
301+ 
302+         # Send a successful discovery response with minimal protected resource metadata 
303+         discovery_response  =  httpx .Response (
304+             200 ,
305+             content = b'{"resource": "https://api.example.com/v1/mcp", "authorization_servers": ["https://auth.example.com/v1/mcp"]}' ,
306+             request = discovery_request ,
307+         )
308+ 
309+         # Next request should be to discover OAuth metadata 
310+         oauth_metadata_request_1  =  await  auth_flow .asend (discovery_response )
311+         assert  (
312+             str (oauth_metadata_request_1 .url )
313+             ==  "https://auth.example.com/.well-known/oauth-authorization-server/v1/mcp" 
314+         )
315+         assert  oauth_metadata_request_1 .method  ==  "GET" 
316+ 
317+         # Send a 404 response 
318+         oauth_metadata_response_1  =  httpx .Response (
319+             404 ,
320+             content = b"Not Found" ,
321+             request = oauth_metadata_request_1 ,
322+         )
323+ 
324+         # Next request should be to discover OAuth metadata at the next endpoint 
325+         oauth_metadata_request_2  =  await  auth_flow .asend (oauth_metadata_response_1 )
326+         assert  str (oauth_metadata_request_2 .url ) ==  "https://auth.example.com/.well-known/oauth-authorization-server" 
327+         assert  oauth_metadata_request_2 .method  ==  "GET" 
328+ 
329+         # Send a 400 response 
330+         oauth_metadata_response_2  =  httpx .Response (
331+             400 ,
332+             content = b"Bad Request" ,
333+             request = oauth_metadata_request_2 ,
334+         )
335+ 
336+         # Next request should be to discover OAuth metadata at the next endpoint 
337+         oauth_metadata_request_3  =  await  auth_flow .asend (oauth_metadata_response_2 )
338+         assert  str (oauth_metadata_request_3 .url ) ==  "https://auth.example.com/.well-known/openid-configuration/v1/mcp" 
339+         assert  oauth_metadata_request_3 .method  ==  "GET" 
340+ 
341+         # Send a 500 response 
342+         oauth_metadata_response_3  =  httpx .Response (
343+             500 ,
344+             content = b"Internal Server Error" ,
345+             request = oauth_metadata_request_3 ,
346+         )
347+ 
348+         # Mock the authorization process to minimize unnecessary state in this test 
349+         oauth_provider ._perform_authorization  =  mock .AsyncMock (return_value = ("test_auth_code" , "test_code_verifier" ))
350+ 
351+         # Next request should fall back to legacy behavior and auth with the RS (mocked /authorize, next is /token) 
352+         token_request  =  await  auth_flow .asend (oauth_metadata_response_3 )
353+         assert  str (token_request .url ) ==  "https://api.example.com/token" 
354+         assert  token_request .method  ==  "POST" 
355+ 
356+         # Send a successful token response 
357+         token_response  =  httpx .Response (
358+             200 ,
359+             content = (
360+                 b'{"access_token": "new_access_token", "token_type": "Bearer", "expires_in": 3600, ' 
361+                 b'"refresh_token": "new_refresh_token"}' 
362+             ),
363+             request = token_request ,
364+         )
365+         token_request  =  await  auth_flow .asend (token_response )
366+ 
264367    @pytest .mark .anyio  
265368    async  def  test_handle_metadata_response_success (self , oauth_provider ):
266369        """Test successful metadata response handling.""" 
0 commit comments