Skip to content

feat: fix OAuth redirect_uri hint for proxied/iframe deployments#4417

Open
madhav165 wants to merge 4 commits intomainfrom
feat/oauth-redirect-proxy
Open

feat: fix OAuth redirect_uri hint for proxied/iframe deployments#4417
madhav165 wants to merge 4 commits intomainfrom
feat/oauth-redirect-proxy

Conversation

@madhav165
Copy link
Copy Markdown
Collaborator

✨ Feature / Enhancement PR

🔗 Epic / Issue

Closes #4354


🚀 Summary (1-2 sentences)

Add ForwardedHostMiddleware that rewrites the ASGI host header from X-Forwarded-Host, so that request.base_url reflects the proxy's public address when the gateway is behind a reverse proxy. This fixes the OAuth redirect_uri hint in the admin UI showing the gateway's internal address instead of the proxy URL.


🧪 Checks

  • make lint passes
  • make test passes
  • CHANGELOG updated (if user-facing)

📓 Notes

Problem

The admin UI shows an OAuth redirect_uri hint (💡 Use: {base_url}oauth/callback) on gateway and A2A agent add/edit forms. When the gateway is behind a reverse proxy, this hint shows the internal gateway address because Uvicorn's ProxyHeadersMiddleware handles X-Forwarded-Proto (scheme) and X-Forwarded-For (client IP) but not X-Forwarded-Host (host). This is a known upstream gap: encode/uvicorn#965, with an unmerged PR #2811.

Solution

A small ASGI middleware (ForwardedHostMiddleware) registered alongside ProxyHeadersMiddleware that:

  • Reads X-Forwarded-Host, takes the first comma-separated value
  • Parses optional port (including IPv6 bracket notation)
  • Rewrites the host header in scope["headers"] and the scope["server"] tuple
  • No template changes needed — all 4 hint locations are fixed automatically

Security review

  • OAuth audience binding (_build_server_resource_url): uses settings.app_domain, immune to host rewriting
  • SSO redirect validation: uses settings.app_domain + allowlist, immune
  • CSRF origin check: already reads X-Forwarded-Host directly (pre-existing), no regression
  • trusted_hosts="*": pre-existing decision on ProxyHeadersMiddleware, not introduced by this change

Files changed

File Change
mcpgateway/middleware/forwarded_host.py New middleware
mcpgateway/main.py Import + register middleware
tests/unit/mcpgateway/middleware/test_forwarded_host_middleware.py 15 unit tests
tests/playwright/test_forwarded_host_redirect_hint.py 2 Playwright E2E tests

Can be removed when Uvicorn merges upstream X-Forwarded-Host support.

…hint

Uvicorn's ProxyHeadersMiddleware handles X-Forwarded-Proto (scheme) and
X-Forwarded-For (client IP) but not X-Forwarded-Host. When the gateway
is behind a reverse proxy, request.base_url still shows the internal
host, causing the OAuth redirect_uri hint in the admin UI to display
the wrong callback URL.

Add ForwardedHostMiddleware that rewrites the ASGI host header and
scope["server"] from X-Forwarded-Host, making request.base_url
reflect the proxy's public address. This fixes the redirect_uri hint
in all four add/edit gateway and A2A agent forms without template changes.

The middleware mirrors the approach in Uvicorn PR #2811 (Kludex/uvicorn#965)
and can be removed when upstream merges that support.

Closes #4354

Signed-off-by: Madhav Kandukuri <madhav165@gmail.com>
…limitations

Extract _proxy_trusted_hosts variable so ProxyHeadersMiddleware and
ForwardedHostMiddleware always use the same trust setting. Document
that ForwardedHostMiddleware only acts for wildcard trust (no per-IP
checking) and that default port values follow RFC 2616.

Signed-off-by: Madhav Kandukuri <madhav165@gmail.com>
The middleware had a trusted_hosts parameter that was a no-op for
non-wildcard values, making it look like it did per-IP trust checking
when it did not. Remove the parameter entirely -- trust decisions
belong to the caller (main.py gates registration). Also clean up
docstrings to document port parsing behavior accurately.

Signed-off-by: Madhav Kandukuri <madhav165@gmail.com>
- Swap registration order so ForwardedHostMiddleware is inner to
  ProxyHeadersMiddleware, ensuring scope["scheme"] is already corrected
  when deriving the default port for scope["server"].
- Replace uvicorn._types imports with stdlib typing equivalents to avoid
  coupling to a private module.
- Inline the trusted_hosts literal instead of a stray module-level constant.
- Update docstring to match the corrected registration order.

Signed-off-by: Madhav Kandukuri <madhav165@gmail.com>
@madhav165 madhav165 added ica ICA related issues release-fix Critical bugfix required for the release ui User Interface labels Apr 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ica ICA related issues release-fix Critical bugfix required for the release ui User Interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Fix OAuth redirect_uri hint for proxied/iframe deployments

1 participant