Skip to content

fix(transport): include app_root_path in enforced OAuth audience#5498

Open
C0d3N1nja97342 wants to merge 1 commit into
IBM:mainfrom
C0d3N1nja97342:fix/5172-resource-url-app-root-path
Open

fix(transport): include app_root_path in enforced OAuth audience#5498
C0d3N1nja97342 wants to merge 1 commit into
IBM:mainfrom
C0d3N1nja97342:fix/5172-resource-url-app-root-path

Conversation

@C0d3N1nja97342

@C0d3N1nja97342 C0d3N1nja97342 commented Jul 5, 2026

Copy link
Copy Markdown

🔗 Related Issue

Closes #5172

📝 Summary

_build_server_resource_url in mcpgateway/transports/streamablehttp_transport.py derives the enforced access-token aud from settings.app_domain only (f"{app_domain}/servers/{id}/mcp"), dropping app_root_path. On path-prefixed deployments (APP_ROOT_PATH set — e.g. gateway mounted under /gw behind an ingress), this diverges from the advertised Protected Resource Metadata URL, which is built via _build_public_base_url and includes scope["root_path"]:

  • advertised resource: {scheme}://{host}{root_path}/servers/{id}/mcp
  • enforced aud: {APP_DOMAIN}/servers/{id}/mcp ← missing root_path

So tokens minted for the advertised resource fail audience validation on path-prefixed deployments.

Fix: include settings.app_root_path between app_domain and /servers/ in the enforced audience. Backward compatible — an empty app_root_path leaves the URL unchanged.

📏 Reviewability

🏷️ Type of Change

  • Bug fix

Changes

  • mcpgateway/transports/streamablehttp_transport.py: _build_server_resource_url now appends settings.app_root_path (normalized: stripped, leading / ensured) between app_domain and /servers/{id}/mcp.
  • tests/unit/mcpgateway/transports/test_streamablehttp_transport.py: two tests — app_root_path="/gw" → URL includes /gw; empty app_root_path → URL unchanged.

Testing

  • New tests pass: uv run pytest tests/unit/mcpgateway/transports/test_streamablehttp_transport.py -k build_server_resource_url → 2 passed.
  • No regression in the OAuth audience/auth suite: uv run pytest tests/unit/mcpgateway/test_auth.py -k "resource or audience or canonical or oauth" → 111 passed.
  • ruff check clean on the changed file.

Notes for Reviewer

  • The fix mirrors how _build_public_base_url already includes scope["root_path"], using the operator-set settings.app_root_path (same trust anchor as app_domain, consistent with the function's existing security note).
  • The fix is intentionally minimal and scoped to _build_server_resource_url (the enforced-aud path). The advertised-resource path (_build_resource_metadata_url_build_public_base_url) already includes root_path and is unchanged.
  • IBM CLA: I will sign via cla-assistant once it checks this PR.

Issue IBM#5172: _build_server_resource_url derived the enforced access-token aud from settings.app_domain only (f'{app_domain}/servers/{id}/mcp'), dropping app_root_path. On path-prefixed deployments (APP_ROOT_PATH set, e.g. gateway mounted under /gw), this diverged from the advertised Protected Resource Metadata URL (built via _build_public_base_url, which includes scope root_path) — so tokens minted for the advertised resource failed audience validation.

Include settings.app_root_path between app_domain and /servers/ in the enforced audience. Backward compatible: empty app_root_path leaves the URL unchanged.

Adds two tests: root_path included when set; URL unchanged when app_root_path is empty.

Signed-off-by: keaixiaozhu <keaipiglet@163.com>
@C0d3N1nja97342 C0d3N1nja97342 force-pushed the fix/5172-resource-url-app-root-path branch from d33189d to 0f2663f Compare July 5, 2026 04:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Inbound OAuth audience enforcement ignores APP_ROOT_PATH — enforced aud ≠ advertised PRM resource on path-prefixed deployments

1 participant