π Bug Summary
The stateful session fallback auth path in _get_request_context_or_default() resolves user identity through require_auth_override() β require_auth(), which prioritizes cookie tokens over Authorization headers. The primary middleware auth path (streamable_http_auth) uses Authorization header only. If a request carries both a valid Authorization header and a different valid cookie JWT, the middleware authenticates as the header user but the fallback authenticates as the cookie user, causing identity drift.
π§© Affected Component
π Steps to Reproduce
- Enable stateful sessions (
USE_STATEFUL_SESSIONS=true)
- Send a request to
/servers/{id}/mcp/ with:
Authorization: Bearer <token-for-user-A>
- Cookie
jwt_token=<token-for-user-B>
- On the initial request,
streamable_http_auth authenticates as user A (header only)
- On a subsequent request where ContextVars are stale,
_get_request_context_or_default() falls back and authenticates as user B (cookie takes precedence in require_auth)
π€ Expected Behavior
The fallback auth path should use the same token precedence as the middleware β Authorization header first, cookie as fallback only when no header is present.
π Code References
- Middleware (header-only):
mcpgateway/transports/streamablehttp_transport.py:2200-2205
- Fallback calls
require_auth_override: mcpgateway/transports/streamablehttp_transport.py:1002
require_auth token precedence (cookie first): mcpgateway/utils/verify_credentials.py:389-401
π‘ Suggested Fix
In _get_request_context_or_default(), align token precedence with middleware by only passing the cookie when no Authorization header is present:
auth_header = req_headers.get("authorization")
cookie_token = request.cookies.get("jwt_token") if not auth_header else None
Or create a dedicated require_auth_header_first() variant that matches the middleware's precedence.
π Practical Risk Assessment
Low practical risk β this only triggers when:
- Stateful session ContextVars are stale (fallback fires)
- Request carries BOTH a valid Authorization header AND a different valid cookie JWT
- MCP SDK clients use headers (not cookies); browser Admin UI uses cookies (not MCP transport)
The scenario of both being present with different identities is unusual in practice.
| Key |
Value |
| Version or commit |
main (pre-existing, noted during PR #2974 review) |
| Runtime |
Python 3.13 |
| Severity |
Medium (requires unusual conditions, but could cause authorization inconsistency) |
π Bug Summary
The stateful session fallback auth path in
_get_request_context_or_default()resolves user identity throughrequire_auth_override()βrequire_auth(), which prioritizes cookie tokens over Authorization headers. The primary middleware auth path (streamable_http_auth) uses Authorization header only. If a request carries both a valid Authorization header and a different valid cookie JWT, the middleware authenticates as the header user but the fallback authenticates as the cookie user, causing identity drift.π§© Affected Component
mcpgateway- APIπ Steps to Reproduce
USE_STATEFUL_SESSIONS=true)/servers/{id}/mcp/with:Authorization: Bearer <token-for-user-A>jwt_token=<token-for-user-B>streamable_http_authauthenticates as user A (header only)_get_request_context_or_default()falls back and authenticates as user B (cookie takes precedence inrequire_auth)π€ Expected Behavior
The fallback auth path should use the same token precedence as the middleware β Authorization header first, cookie as fallback only when no header is present.
π Code References
mcpgateway/transports/streamablehttp_transport.py:2200-2205require_auth_override:mcpgateway/transports/streamablehttp_transport.py:1002require_authtoken precedence (cookie first):mcpgateway/utils/verify_credentials.py:389-401π‘ Suggested Fix
In
_get_request_context_or_default(), align token precedence with middleware by only passing the cookie when no Authorization header is present:Or create a dedicated
require_auth_header_first()variant that matches the middleware's precedence.π Practical Risk Assessment
Low practical risk β this only triggers when:
The scenario of both being present with different identities is unusual in practice.
main(pre-existing, noted during PR #2974 review)Python 3.13