fix: not authenticate API with Cookies. Returns response 401 instead 200#2680
fix: not authenticate API with Cookies. Returns response 401 instead 200#2680crivetimihai merged 2 commits intomainfrom
Conversation
|
Clean security fix — the approach of tracking token source and rejecting cookie-only auth for non-browser requests is sound. CI is all green, tests are updated correctly. One minor note: a client could technically bypass the check by including LGTM — ready to merge. |
Signed-off-by: Marek Dano <mk.dano@gmail.com>
Verify that cookie-only authentication returns 401 for non-browser API requests (Accept: application/json), ensuring the security fix is explicitly covered by tests. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
f127f14 to
cc5db05
Compare
crivetimihai
left a comment
There was a problem hiding this comment.
Review Notes
Rebased onto current main (clean, no conflicts) and added a missing test.
Changes made during review
- Rebased onto
main(26f1f3e) - Added test
test_get_current_user_with_permissions_cookie_rejected_for_api_request— verifies that an API request (Accept: application/json) with cookie-only auth and noAuthorizationheader correctly returns401with the expected error message. The original PR updated existing tests to accommodate the new behavior but didn't include a positive assertion for the rejection itself.
Review findings
Logic & correctness: Sound. The token source priority is correctly reordered (Authorization header → cookies → FastAPI Cookie dependency), token_from_cookie tracking is accurate, and the browser detection heuristic (Accept: text/html or hx-request) is consistent with the rest of the codebase.
Security: Good defense-in-depth. The Accept header heuristic can be spoofed, but this is acceptable — the primary CSRF defense is the existing SameSite=Lax cookie attribute. This change prevents accidental cookie-based auth from API clients.
Consistency: No conflicts with other cookie-reading patterns in the codebase:
auth_middleware.pyreads cookies for informational context (logging), not enforcement — unaffectedmain.pycookie reads are for admin UI routes (HTML) or run after RBAC auth — unaffected- MCP transports (SSE, WebSocket, streamable HTTP) use Authorization headers exclusively — unaffected
llmchat_router.pycookie read is for forwarding credentials to downstream MCP servers, not user auth — unaffected
Tests: All 6520 unit tests pass. All 284 middleware tests pass (including the new one).
PR #2680 introduced a check that rejects cookie-only authentication for API requests to prevent CSRF-style attacks from external callers. However, the admin UI's JavaScript fetch() calls (fetchWithTimeout, etc.) send Accept: */* or application/json — not text/html — so they were incorrectly rejected with 401 Unauthorized. Fix by also checking the Referer header for /admin to identify requests originating from the admin UI. The browser automatically sets this header on same-origin fetch calls, so admin UI AJAX requests are correctly recognized as legitimate while external API callers without an admin Referer are still blocked. Also relax the unix socket throughput test threshold (50 → 10 calls/sec) to prevent flaky failures in CI/slow environments. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
PR #2680 introduced a check that rejects cookie-only authentication for API requests to prevent CSRF-style attacks from external callers. However, the admin UI's JavaScript fetch() calls (fetchWithTimeout, etc.) send Accept: */* or application/json — not text/html — so they were incorrectly rejected with 401 Unauthorized. Fix by also checking the Referer header for /admin to identify requests originating from the admin UI. The browser automatically sets this header on same-origin fetch calls, so admin UI AJAX requests are correctly recognized as legitimate while external API callers without an admin Referer are still blocked. Also relax the unix socket throughput test threshold (50 → 10 calls/sec) to prevent flaky failures in CI/slow environments. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…200 (IBM#2680) * fix: not authenticate API with Cookies. Returns response 401 instead 200 Signed-off-by: Marek Dano <mk.dano@gmail.com> * test: add test for cookie rejection on API requests Verify that cookie-only authentication returns 401 for non-browser API requests (Accept: application/json), ensuring the security fix is explicitly covered by tests. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Marek Dano <mk.dano@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
PR IBM#2680 introduced a check that rejects cookie-only authentication for API requests to prevent CSRF-style attacks from external callers. However, the admin UI's JavaScript fetch() calls (fetchWithTimeout, etc.) send Accept: */* or application/json — not text/html — so they were incorrectly rejected with 401 Unauthorized. Fix by also checking the Referer header for /admin to identify requests originating from the admin UI. The browser automatically sets this header on same-origin fetch calls, so admin UI AJAX requests are correctly recognized as legitimate while external API callers without an admin Referer are still blocked. Also relax the unix socket throughput test threshold (50 → 10 calls/sec) to prevent flaky failures in CI/slow environments. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
🐛 Bug-fix PR
Issue reported at https://github.ibm.com/contextforge-org/mcp-context-forge/issues/3
Relates #2409
📌 Summary
What problem does this PR fix and why?
The issue is that API requests with cookies only (no Authorization header) are returning 200 OK instead of 401 Unauthorized.
The problem is that cookies are being accepted as valid authentication. According to the task, we should reject cookie-only authentication for API requests.
The key is to distinguish between browser requests (which should use cookies) and API requests (which should use Authorization header only).
The fix should be:
🔁 Reproduction Steps
All APIs return 200 OK
🐞 Root Cause
What was wrong and where?
The user wants API requests with cookies only to return 401 instead of 200. I've identified the issue in
mcpgateway/middleware/rbac.pywhere theget_current_user_with_permissionsfunction accepts tokens from cookies for all requests.💡 Fix Description
How did you solve it? Key design points.
I've applied a fix that:
🧪 Verification
make lintmake testmake coverage📐 MCP Compliance (if relevant)
✅ Checklist
make black isort pre-commit)