@@ -343,9 +343,14 @@ async def oauth_authorization_server_metadata(request):
343343 status_code = 500 ,
344344 )
345345
346+ suffix = mcp_path or ""
346347 routes .append (
347- Route ("/.well-known/oauth-authorization-server" , endpoint = oauth_authorization_server_metadata , methods = ["GET" ])
348+ Route (f "/.well-known/oauth-authorization-server{ suffix } " , endpoint = oauth_authorization_server_metadata , methods = ["GET" ])
348349 )
350+ if suffix :
351+ routes .append (
352+ Route ("/.well-known/oauth-authorization-server" , endpoint = oauth_authorization_server_metadata , methods = ["GET" ])
353+ )
349354
350355 async def register_client_fix_auth_method (request ):
351356 """Minimal DCR proxy that fixes token_endpoint_auth_method in Keycloak's response."""
@@ -467,11 +472,12 @@ def __init__(
467472 audience = audience ,
468473 )
469474
470- # OBP-OIDC is advertised directly as the authorization server
471- # No proxy needed - OBP-OIDC has native DCR support with correct token_endpoint_auth_method
475+ # Advertise ourselves as the authorization server so all discovery and DCR
476+ # flows route through our proxy — this lets us fix incompatibilities in
477+ # OBP-OIDC's responses (e.g. null fields in DCR) before they reach clients.
472478 super ().__init__ (
473479 token_verifier = token_verifier ,
474- authorization_servers = [AnyHttpUrl ( self .issuer_url ) ],
480+ authorization_servers = [self .base_url ],
475481 base_url = self .base_url ,
476482 )
477483
@@ -499,6 +505,11 @@ async def forward_oauth_authorization_server_metadata(request):
499505 )
500506 response .raise_for_status ()
501507 metadata = response .json ()
508+
509+ # Route DCR through our proxy so we can fix null fields
510+ base_url = str (self .base_url ).rstrip ("/" )
511+ metadata ["registration_endpoint" ] = f"{ base_url } /register"
512+
502513 return JSONResponse (metadata )
503514 except httpx .HTTPStatusError as e :
504515 logger .error (f"Failed to fetch OBP-OIDC metadata: { e } " )
@@ -523,6 +534,11 @@ async def forward_openid_configuration(request):
523534 )
524535 response .raise_for_status ()
525536 metadata = response .json ()
537+
538+ # Route DCR through our proxy so we can fix null fields
539+ base_url = str (self .base_url ).rstrip ("/" )
540+ metadata ["registration_endpoint" ] = f"{ base_url } /register"
541+
526542 return JSONResponse (metadata )
527543 except httpx .HTTPStatusError as e :
528544 logger .error (f"Failed to fetch OBP-OIDC openid-configuration: { e } " )
@@ -555,11 +571,17 @@ async def forward_register(request):
555571 registration_endpoint = f"{ self .issuer_url } /connect/register"
556572 response = await client .post (registration_endpoint , content = body , headers = forward_headers )
557573
558- # Forward the response as-is (OBP-OIDC returns correct token_endpoint_auth_method)
559- return JSONResponse (
560- response .json () if response .headers .get ("content-type" , "" ).startswith ("application/json" ) else {"error" : "registration_failed" },
561- status_code = response .status_code ,
562- )
574+ if not response .headers .get ("content-type" , "" ).startswith ("application/json" ):
575+ return JSONResponse ({"error" : "registration_failed" }, status_code = response .status_code )
576+
577+ client_info = response .json ()
578+
579+ # Strip null values — OBP-OIDC returns nulls for optional fields
580+ # (client_uri, logo_uri, contacts) that strict clients expect to be
581+ # absent rather than null
582+ client_info = {k : v for k , v in client_info .items () if v is not None }
583+
584+ return JSONResponse (client_info , status_code = response .status_code )
563585
564586 except Exception as e :
565587 logger .error (f"DCR forward error: { e } " )
@@ -568,13 +590,23 @@ async def forward_register(request):
568590 status_code = 500 ,
569591 )
570592
571- # Add forwarding routes for clients that fetch from the resource server
593+ # Add forwarding routes at both paths:
594+ # - With mcp_path suffix: for RFC 8414 path-aware discovery from MCP endpoint URL
595+ # - Without suffix: for OASM discovery from authorization_servers URL (no path)
596+ suffix = mcp_path or ""
572597 routes .append (
573- Route ("/.well-known/oauth-authorization-server" , endpoint = forward_oauth_authorization_server_metadata , methods = ["GET" ])
598+ Route (f "/.well-known/oauth-authorization-server{ suffix } " , endpoint = forward_oauth_authorization_server_metadata , methods = ["GET" ])
574599 )
575600 routes .append (
576- Route ("/.well-known/openid-configuration" , endpoint = forward_openid_configuration , methods = ["GET" ])
601+ Route (f "/.well-known/openid-configuration{ suffix } " , endpoint = forward_openid_configuration , methods = ["GET" ])
577602 )
603+ if suffix :
604+ routes .append (
605+ Route ("/.well-known/oauth-authorization-server" , endpoint = forward_oauth_authorization_server_metadata , methods = ["GET" ])
606+ )
607+ routes .append (
608+ Route ("/.well-known/openid-configuration" , endpoint = forward_openid_configuration , methods = ["GET" ])
609+ )
578610 routes .append (
579611 Route ("/register" , endpoint = forward_register , methods = ["POST" ])
580612 )
0 commit comments