[FIX][UI]: Fix OAuth tool fetching#3062
Conversation
crivetimihai
left a comment
There was a problem hiding this comment.
This works around the 401, but the approach has issues:
-
Fake
hx-request: trueheader — this is not an HTMX request. It's a plainfetch()from inline JS. Any middleware or logging that branches onhx-requestwill misclassify this request. -
Accept: text/htmlis semantically wrong — the endpoint returns JSON ({"success": true, "message": "..."}), and the response handler callsresponse.json(). Claiming the client wants HTML back is misleading. -
Incomplete — doesn't fix
admin.js:19594fetchToolsForGateway()(which has the same pattern), and doesn't addcredentials: "include"for cross-origin safety.
The underlying issue (as documented in #3059) is that the RBAC referer check at rbac.py:259 only matches "/admin" in referer. The OAuth success page's referer is /oauth/callback, which doesn't match.
The cleaner fix would be:
rbac.py:259: Broadenis_admin_ui_requestto also match/oauth/in the refereroauth_router.py+admin.js: Addcredentials: "include"(defensive, for cross-origin deployments)
That way no fake headers are needed, and both call sites are covered.
crivetimihai
left a comment
There was a problem hiding this comment.
Thanks @madhav165 — this is exactly the right fix. Clean and correct.
What changed (all good):
-
rbac.py— broadened the referer check to include/oauth/:is_admin_ui_request = "/admin" in referer or "/oauth/" in referer
This correctly treats the OAuth callback page as a browser request, allowing cookie auth to pass through.
-
oauth_router.py+admin.js— addedcredentials: 'include'to thefetch-toolscall, so the browser actually sends thejwt_tokencookie with the request. -
Tests — three solid cases covering admin referer (allowed), OAuth referer (allowed), and unrelated referer (rejected). Good coverage of the boundary.
The fake-header approach from the earlier revision is gone, and the fix works at the right layer (referer-based browser detection + standard cookie inclusion). LGTM.
988a761 to
d6d2f91
Compare
crivetimihai
left a comment
There was a problem hiding this comment.
LGTM — clean, minimal fix with good test coverage.
Rebased onto main and squashed into a single commit.
Changes reviewed:
credentials: 'include'on both fetch() calls (oauth callback page + admin.js) — consistent with ~18 other admin.js fetch calls/oauth/referer detection in RBAC middleware — mirrors existing/adminpattern- 3 new unit tests covering admin referer, oauth referer, and unrelated referer rejection
- 100% line coverage on
mcpgateway/middleware/rbac.py
Security: No concerns — referer is browser-enforced (same-origin policy), cookies are httponly + samesite=lax, and cookie auth remains a secondary mechanism behind Bearer tokens.
Add `credentials: 'include'` to the fetch-tools request in both the OAuth callback page and admin.js so the browser sends the jwt_token cookie. The OAuth callback fetch also sets `Accept: text/html` so the RBAC middleware recognises it as a browser request through the existing accept-header check, avoiding the need to expand referer-based trust to `/oauth/` paths. Closes #3059 Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
d6d2f91 to
c2a0341
Compare
Security hardening: replaced referer-based
|
| File | Change |
|---|---|
oauth_router.py |
credentials: 'include' + Accept: text/html on callback fetch |
admin.js |
credentials: 'include' on admin fetch (referer /admin handles detection) |
test_rbac.py |
+4 tests: admin referer allow, accept-header allow, cross-origin reject, unrelated referer reject |
All 168 tests pass, 100% coverage on rbac.py.
|
Acknowledged the Referrer-Policy nuance — our header governs responses from our app, not attacker-controlled pages. The browser default ( The pre-existing This is ready to merge. |
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* fix(ui): fix OAuth tool fetching cookie auth Add `credentials: 'include'` to the fetch-tools request in both the OAuth callback page and admin.js so the browser sends the jwt_token cookie. The OAuth callback fetch also sets `Accept: text/html` so the RBAC middleware recognises it as a browser request through the existing accept-header check, avoiding the need to expand referer-based trust to `/oauth/` paths. Closes #3059 Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * Fix pre-commit Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Madhav Kandukuri <madhav165@gmail.com> Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
🐛 Bug-fix PR
Closes #3059
📌 Summary
Fixes a bug where clicking "Fetch Tools" button in the OAuth callback page returns a 401 error with message "Cookie authentication not allowed for API requests. Use Authorization header."
🐞 Root Cause
The RBAC middleware (
mcpgateway/middleware/rbac.py) rejects cookie-only authentication for non-browser requests. The fetch request from the OAuth callback page was missing:hx-request: "true",Accept: text/html)Without these, the request was treated as an API request, triggering the 401 error.
💡 Fix Description
mcpgateway/routers/oauth_router.py
Added browser identification headers to the fetch request in the OAuth callback template:
const response = await fetch('{safe_root_path}/oauth/fetch-tools/{escape(str(gateway_id))}', { - method: 'POST' + method: 'POST', + headers: { + 'hx-request': 'true', + 'Accept': 'text/html' + } });🧪 Verification
make lintmake test📐 MCP Compliance (if relevant)
✅ Checklist
make black isort pre-commit)