From 599f3a0e9c23329c10cb65be25832a407ea5745d Mon Sep 17 00:00:00 2001 From: TheEdgeOfRage Date: Tue, 28 Jul 2026 01:41:02 +0200 Subject: [PATCH] fix: normalize OAuth server metadata URLs --- backend/open_webui/routers/configs.py | 5 ++++- backend/open_webui/utils/oauth.py | 7 +++++-- backend/open_webui/utils/oauth_metadata.py | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 backend/open_webui/utils/oauth_metadata.py diff --git a/backend/open_webui/routers/configs.py b/backend/open_webui/routers/configs.py index 5235a3108c..6a0872cd49 100644 --- a/backend/open_webui/routers/configs.py +++ b/backend/open_webui/routers/configs.py @@ -15,6 +15,7 @@ from open_webui.models.oauth_sessions import OAuthSessions from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.utils.headers import get_custom_headers from open_webui.utils.mcp.client import MCPClient +from open_webui.utils.oauth_metadata import normalize_oauth_metadata from open_webui.utils.oauth import ( OAuthClientInformationFull, apply_connection_oauth_options, @@ -568,7 +569,9 @@ async def verify_tool_servers_config(request: Request, form_data: ToolServerConn if oauth_server_metadata_response.status == 200: try: oauth_server_metadata = OAuthMetadata.model_validate( - await oauth_server_metadata_response.json() + normalize_oauth_metadata( + await oauth_server_metadata_response.json(), discovery_url + ) ) return { 'status': True, diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index aac22c9436..847700bed1 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -88,6 +88,7 @@ from open_webui.retrieval.web.utils import get_ssrf_safe_session, validate_url from open_webui.utils.auth import create_token, get_password_hash from open_webui.utils.groups import apply_default_group_assignment from open_webui.utils.misc import parse_duration +from open_webui.utils.oauth_metadata import normalize_oauth_metadata from open_webui.utils.validate import validate_profile_image_url from starlette.responses import RedirectResponse @@ -535,7 +536,7 @@ async def get_oauth_client_info_with_dynamic_client_registration( if oauth_server_metadata_response.status == 200: try: oauth_server_metadata = OAuthMetadata.model_validate( - await oauth_server_metadata_response.json() + normalize_oauth_metadata(await oauth_server_metadata_response.json(), url) ) oauth_server_metadata_url = url if ( @@ -663,7 +664,9 @@ async def get_oauth_client_info_with_static_credentials( async with session.get(url, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: if resp.status == 200: try: - oauth_server_metadata = OAuthMetadata.model_validate(await resp.json()) + oauth_server_metadata = OAuthMetadata.model_validate( + normalize_oauth_metadata(await resp.json(), url) + ) oauth_server_metadata_url = url break except Exception as e: diff --git a/backend/open_webui/utils/oauth_metadata.py b/backend/open_webui/utils/oauth_metadata.py new file mode 100644 index 0000000000..fcec17edec --- /dev/null +++ b/backend/open_webui/utils/oauth_metadata.py @@ -0,0 +1,14 @@ +import urllib.parse + + +def normalize_oauth_metadata(metadata: dict, metadata_url: str) -> dict: + normalized = dict(metadata) + parsed_url = urllib.parse.urlparse(metadata_url) + origin = f'{parsed_url.scheme}://{parsed_url.netloc}' + normalized.setdefault('issuer', origin) + + for field, value in normalized.items(): + if isinstance(value, str) and (field == 'issuer' or field.endswith('_endpoint') or field == 'jwks_uri'): + normalized[field] = urllib.parse.urljoin(f'{origin}/', value) + + return normalized