Skip to content

Fix proxy authentication in RBAC middleware for all protected endpoints#2345

Merged
crivetimihai merged 6 commits intomainfrom
1528-proxy-based-authentication-bug
Jan 24, 2026
Merged

Fix proxy authentication in RBAC middleware for all protected endpoints#2345
crivetimihai merged 6 commits intomainfrom
1528-proxy-based-authentication-bug

Conversation

@MohanLaksh
Copy link
Copy Markdown
Collaborator

🐛 Bug-fix PR: Fix proxy authentication in RBAC middleware for all protected endpoints

Title

fix: Support proxy authentication in RBAC middleware for all protected endpoints

Description

Problem

When proxy-based authentication was configured (MCP_CLIENT_AUTH_ENABLED=false, TRUST_PROXY_AUTH=true), all endpoints protected by the @require_permission decorator (including /tools/, /resources/, /prompts/, etc.) were still requiring JWT tokens and rejecting requests with only proxy headers.

The bug was in get_current_user_with_permissions() which only checked for proxy authentication after determining no JWT token was present, and only fell back to AUTH_REQUIRED setting rather than properly handling proxy authentication.

Solution

Modified mcpgateway/middleware/rbac.py to check for proxy authentication before requiring JWT tokens:

  1. When MCP_CLIENT_AUTH_ENABLED=false, check proxy headers first
  2. Extract user from PROXY_USER_HEADER when TRUST_PROXY_AUTH=true
  3. Return anonymous user when proxy auth enabled but no header present
  4. Fall back to standard JWT flow when MCP_CLIENT_AUTH_ENABLED=true

Changes

  • Modified: mcpgateway/middleware/rbac.py - Updated get_current_user_with_permissions() function
  • Added: 4 new unit tests in tests/unit/mcpgateway/utils/test_proxy_auth.py

Testing

  • ✅ All 17 proxy authentication tests pass (13 existing + 4 new)
  • ✅ All RBAC middleware tests pass
  • ✅ Backward compatibility verified with JWT authentication
  • ✅ Tested with multiple endpoints: /tools/, /resources/, /prompts/, /servers/, /gateways/
curl -X GET \
  'http://localhost:4444/tools/?include_inactive=false' \
  -H 'X-Authenticated-User: admin@example.com' \
  -H 'accept: application/json'

Impact

This fix enables proxy-based authentication for all 100+ protected endpoints that use the @require_permission decorator, including:

  • Tools, Resources, Prompts, Servers, Gateways management
  • A2A agents, Tags, Metrics
  • Export/Import functionality
  • And all other RBAC-protected endpoints

Configuration

Works with the following environment variables:

MCP_CLIENT_AUTH_ENABLED=false
TRUST_PROXY_AUTH=true
PROXY_USER_HEADER=X-Authenticated-User
AUTH_REQUIRED=false

Closes #1528

@MohanLaksh
Copy link
Copy Markdown
Collaborator Author

MohanLaksh commented Jan 23, 2026

Passes

make autoflake isort black pre-commit

make doctest test lint-web flake8 bandit interrogate pylint verify

@crivetimihai crivetimihai added this to the Release 1.0.0-RC1 milestone Jan 24, 2026
MohanLakshmaiah and others added 4 commits January 24, 2026 22:11
Signed-off-by: Mohan Lakshmaiah <mohalaks@in.ibm.com>
Signed-off-by: Mohan Lakshmaiah <mohalaks@in.ibm.com>
- Add missing blank line between test classes
- Remove unused jwt import
- Fix excess blank lines

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Add plugin_context_table and plugin_global_context to proxy
authentication paths, matching the JWT authentication path.
This ensures HTTP_AUTH_CHECK_PERMISSION hooks can access context
set by HTTP_PRE_REQUEST hooks when using proxy authentication.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai crivetimihai force-pushed the 1528-proxy-based-authentication-bug branch from 2ce0b27 to 8b81663 Compare January 24, 2026 23:03
1. RBAC now checks auth_required when proxy header missing
   - Returns 401 for API requests, 302 redirect for browsers
   - Aligns HTTP behavior with WebSocket auth

2. Block anonymous users from token management
   - Add auth_method=="anonymous" to _require_interactive_session
   - Prevents token access when proxy header missing

3. Lookup proxy user admin status from database
   - Check platform_admin_email for admin match
   - Query EmailUser table for is_admin status
   - Enables plugin permission hooks to work correctly

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai
Copy link
Copy Markdown
Member

Review Changes Applied

Rebased onto main and applied the following fixes:

1. Lint Fixes

  • Added missing blank line between test classes
  • Removed unused jwt import
  • Fixed excess blank lines

2. Plugin Context for Cross-Hook Sharing

Added plugin_context_table and plugin_global_context to all proxy authentication return paths, matching the JWT authentication path. This ensures HTTP_AUTH_CHECK_PERMISSION hooks can access context set by HTTP_PRE_REQUEST hooks when using proxy authentication.

3. Security Fixes

Issue Fix
auth_required not checked in proxy mode RBAC now returns 401 (API) or 302 redirect (browser) when proxy header missing and auth_required=true. Aligns with WebSocket behavior.
Anonymous users could access token management Added auth_method=="anonymous" to blocked list in _require_interactive_session()
Proxy admin users not recognized Added DB lookup via platform_admin_email check and EmailUser table query for is_admin status

4. New Tests Added

  • test_rbac_proxy_auth_missing_header_returns_401_when_auth_required
  • test_rbac_proxy_auth_missing_header_redirects_browser_when_auth_required
  • test_rbac_proxy_auth_looks_up_admin_status
  • test_rbac_proxy_auth_preserves_plugin_context

Files Changed

  • mcpgateway/middleware/rbac.py (+111 lines)
  • mcpgateway/routers/tokens.py (+10/-1 lines)
  • tests/unit/mcpgateway/utils/test_proxy_auth.py (+170 lines)

Test Results

  • 65 passed, 9 skipped (expected - plugin manager singleton tests)
  • All lint checks pass

Update require_auth to check auth_required when proxy header is
missing, matching the RBAC/WebSocket behavior. Previously returned
"anonymous" even when auth_required=true.

- Raise 401 when mcp_client_auth_enabled=false and no proxy header
  if auth_required=true
- Update tests to cover both auth_required=true and false cases

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai
Copy link
Copy Markdown
Member

Additional Fix: require_auth alignment

Found that require_auth in verify_credentials.py also needed updating to match the new RBAC/WebSocket behavior.

Before: Returned "anonymous" when proxy header missing, ignoring auth_required
After: Raises 401 when auth_required=true and proxy header missing

Added 2 new tests covering both auth_required=true (raises 401) and auth_required=false (returns anonymous) cases.

Files changed:

  • mcpgateway/utils/verify_credentials.py
  • tests/unit/mcpgateway/utils/test_proxy_auth.py

All auth entry points now consistent:

Entry Point No proxy header + auth_required=true
WebSocket Rejects (1008)
Streamable HTTP 401 (uses mcp_require_auth)
RBAC 401/302
require_auth 401 ✅ (now fixed)

@crivetimihai crivetimihai merged commit 6076770 into main Jan 24, 2026
53 checks passed
@crivetimihai crivetimihai deleted the 1528-proxy-based-authentication-bug branch January 24, 2026 23:41
kcostell06 pushed a commit to kcostell06/mcp-context-forge that referenced this pull request Feb 24, 2026
…ts (IBM#2345)

* Fix proxy authentication

Signed-off-by: Mohan Lakshmaiah <mohalaks@in.ibm.com>

* Fix pylint errors

Signed-off-by: Mohan Lakshmaiah <mohalaks@in.ibm.com>

* fix: Correct lint issues in proxy auth tests

- Add missing blank line between test classes
- Remove unused jwt import
- Fix excess blank lines

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: Include plugin context in proxy auth for cross-hook sharing

Add plugin_context_table and plugin_global_context to proxy
authentication paths, matching the JWT authentication path.
This ensures HTTP_AUTH_CHECK_PERMISSION hooks can access context
set by HTTP_PRE_REQUEST hooks when using proxy authentication.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: Address security concerns in proxy authentication

1. RBAC now checks auth_required when proxy header missing
   - Returns 401 for API requests, 302 redirect for browsers
   - Aligns HTTP behavior with WebSocket auth

2. Block anonymous users from token management
   - Add auth_method=="anonymous" to _require_interactive_session
   - Prevents token access when proxy header missing

3. Lookup proxy user admin status from database
   - Check platform_admin_email for admin match
   - Query EmailUser table for is_admin status
   - Enables plugin permission hooks to work correctly

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix: Align require_auth with RBAC proxy enforcement

Update require_auth to check auth_required when proxy header is
missing, matching the RBAC/WebSocket behavior. Previously returned
"anonymous" even when auth_required=true.

- Raise 401 when mcp_client_auth_enabled=false and no proxy header
  if auth_required=true
- Update tests to cover both auth_required=true and false cases

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Mohan Lakshmaiah <mohalaks@in.ibm.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mohan Lakshmaiah <mohalaks@in.ibm.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
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]: Ignores proxy-based authentication configuration and still requires token

3 participants