fix(mcp): strip default port from get_request_base_url netloc

get_request_base_url appended X-Forwarded-Port unconditionally when
building the netloc, producing redirect_uri values like
https://host:443/callback. Providers that canonicalize and exact-match
the registered redirect URI rejected the flow.

Apply _strip_default_port (already in oauth_utils) to the constructed
netloc before returning so :443 for HTTPS and :80 for HTTP are dropped.
This commit is contained in:
devin-ai-integration[bot] 2026-07-01 04:16:46 +00:00 • committed by GitHub
parent 70eb4e5d00
commit 842959cc60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 33 additions and 0 deletions

View file

@ -129,6 +129,7 @@ def get_request_base_url(request: Request) -> str:
if x_forwarded_port and ":" not in netloc:
netloc = f"{netloc}:{x_forwarded_port}"
netloc = _strip_default_port(scheme, netloc)
return urlunparse((scheme, netloc, parsed.path, "", "", ""))

View file

@ -1103,6 +1103,38 @@ async def test_token_endpoint_respects_x_forwarded_host():
None,
"https://external.com",
),
# Case 15: X-Forwarded-Port 443 with HTTPS must NOT appear in the URL
(
"http://localhost:4000/",
"https",
"proxy.example.com",
"443",
"https://proxy.example.com",
),
# Case 16: X-Forwarded-Port 80 with HTTP must NOT appear in the URL
(
"http://localhost:4000/",
"http",
"proxy.example.com",
"80",
"http://proxy.example.com",
),
# Case 17: X-Forwarded-Port 443 without X-Forwarded-Host (portless base)
(
"http://internal.local/",
"https",
None,
"443",
"https://internal.local",
),
# Case 18: Non-default port is preserved
(
"http://localhost:4000/",
"https",
"proxy.example.com",
"8443",
"https://proxy.example.com:8443",
),
],
)
def test_get_request_base_url_comprehensive(