fix(mcp): enforce auth on /streamable for auth_type=oauth projects#12756
fix(mcp): enforce auth on /streamable for auth_type=oauth projects#12756erichare wants to merge 5 commits intorelease-1.10.0from
Conversation
…rojects Previously, projects configured with auth_type=oauth did not enforce authentication on the /streamable (and /sse) endpoints when MCP Composer was enabled. verify_project_auth only enforced API key authentication for auth_type=apikey; for oauth it fell through to the superuser fallback, returning HTTP 200 with full initialize/tools/list payloads to unauthenticated requests. This treats auth_type=oauth the same as auth_type=apikey on the direct langflow MCP transport endpoints: requests must present a valid API key or they are rejected with HTTP 401. End users of OAuth-configured projects should continue to connect via the configured MCP Composer OAuth endpoint (which proxies to these endpoints with backend credentials).
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
❌ Your patch check has failed because the patch coverage (20.00%) is below the target coverage (40.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## release-1.10.0 #12756 +/- ##
==================================================
- Coverage 52.80% 52.73% -0.08%
==================================================
Files 2025 2025
Lines 184053 183350 -703
Branches 28838 26108 -2730
==================================================
- Hits 97191 96685 -506
+ Misses 85767 85571 -196
+ Partials 1095 1094 -1
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
…ment Address review feedback on PR #12756. Requiring an API key for every OAuth request would have broken the intended MCP Composer proxy path: the composer subprocess is started with only the Langflow endpoint URL and OAuth env vars and does not currently inject a backend x-api-key when it forwards authenticated OAuth traffic, so hardening /streamable and /sse would turn every legitimate composer-forwarded request into a 401. Keep the enforcement against direct unauthenticated external access, but trust requests whose direct TCP peer is a loopback address (the on-host MCP Composer subprocess). Remote callers still need a valid x-api-key to hit the project transport endpoints when auth_type=oauth. Add coverage for the loopback passthrough and the _is_loopback_client helper, and gate the rejection tests on a patched non-loopback client so they exercise the remote path even though httpx AsyncClient reports 127.0.0.1 by default.
|
Addressing the P1 review on the composer forwarding path in 52ee309. Context. I looked at Change. Keep the hardening against direct unauthenticated external access, but trust requests whose direct TCP peer ( New / updated coverage in
Follow-up (separate PR). Longer-term, a project-scoped backend key should be provisioned on composer startup and plumbed through so All 44 tests in |
…uth transport Follow-up to PR #12756. The loopback-based passthrough from the prior commit is unsafe in deployments where Langflow sits behind a same-host reverse proxy or sidecar: the proxy becomes the direct TCP peer, so external unauthenticated traffic satisfies the loopback check and falls through to the superuser, reopening the original bypass. There is no composer-specific identity on the wire today — mcp-composer forwards without any Langflow credential — so loopback address cannot distinguish the trusted subprocess from another loopback peer. Require a valid x-api-key on /streamable and /sse for every OAuth project regardless of source. Until mcp-composer can forward a project-scoped backend credential, the composer proxy path will return 401; this is the intended secure behavior. Remove the _is_loopback_client helper, the client_host plumbing into verify_project_auth, and the associated tests. Drop the force_non_loopback_client fixture; the rejection tests now exercise the real code path directly.
|
Agreed — loopback trust is unsafe in reverse-proxy / sidecar deployments where external traffic comes in from the proxy on 127.0.0.1. Reverted in 76d72c9. Now: Tradeoff explicitly taken: until Tests now exercise the real code path directly — no more Yes, please sketch the safer composer-auth handoff design. My current thinking is:
Happy to adjust if you see a cleaner shape. |
The previous message asked callers to connect through MCP Composer, but the composer proxy path currently returns 401 itself (see PR #12756 discussion) because mcp-composer cannot forward a backend credential yet. Describe the actual working path — use an x-api-key — and note that composer-based access is pending credential forwarding support.
Summary
POST /api/v1/mcp/project/{id}/streamable(and/sse) did not enforce authentication for projects configured withauth_type=oauthwhen MCP Composer was enabled.HTTP 200with fullinitializeandtools/listresponses, exposing project tools without any credentials.auth_type=apikeycorrectly rejected unauthenticated requests, confirming the enforcement layer existed but did not trigger for OAuth-configured projects.verify_project_authinsrc/backend/base/langflow/api/v1/mcp_projects.pyonly gated the API-key branch onauth_settings.auth_type == "apikey"; any other value (includingoauth) fell through to aget_user_by_username(SUPERUSER)fallback that returned the superuser without validating any credential.auth_type=oauththe same asauth_type=apikeyon the direct langflow MCP transport endpoints — require a valid API key or returnHTTP 401. OAuth end users should continue to connect via the configured MCP Composer OAuth endpoint, which proxies to these endpoints with backend credentials. Error message for the OAuth case is explicit so developers hitting the endpoint directly understand the correct path.Test plan
src/backend/tests/unit/api/v1/test_mcp_projects.py:test_streamable_rejects_unauthenticated_oauth_project— 401 on no-auth POSTtest_streamable_rejects_unauthenticated_oauth_project_trailing_slash— trailing-slash variant also rejectedtest_sse_rejects_unauthenticated_oauth_project—/sseendpoint also rejectedtest_streamable_oauth_project_accepts_valid_api_key— valid API key still workstest_streamable_oauth_project_rejects_invalid_api_key— bogus API key returns 401 "Invalid API key"test_mcp_projects.pypasses locally (42 tests, 0 failures)AUTO_LOGIN=trueandAUTO_LOGIN=falseboth enforce nowNotes
verify_project_auth; it does not change the behavior forauth_type=apikey,auth_type=nonewithAUTO_LOGIN=true, or the non-composer JWT path.