Skip to content

Commit 36898ef

Browse files
authored
Configurable MCP_CLIENT_AUTH_ENABLED (#710)
Signed-off-by: Mihai Criveti <[email protected]>
1 parent c822fe8 commit 36898ef

File tree

11 files changed

+1331
-19
lines changed

11 files changed

+1331
-19
lines changed

.env.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ TOKEN_EXPIRY=10080
100100
# Require all JWT tokens to have expiration claims (true or false)
101101
REQUIRE_TOKEN_EXPIRATION=false
102102

103+
# MCP Client Authentication (for proxy authentication scenarios)
104+
# Disable JWT authentication for MCP operations (use with caution!)
105+
MCP_CLIENT_AUTH_ENABLED=true
106+
107+
# Trust proxy authentication headers (only set true when behind auth proxy)
108+
TRUST_PROXY_AUTH=false
109+
110+
# Header containing authenticated username from proxy
111+
PROXY_USER_HEADER=X-Authenticated-User
103112

104113
# Used to derive an AES encryption key for secure auth storage
105114
# Must be a non-empty string (e.g. passphrase or random secret)

docs/docs/deployment/proxy-auth.md

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
# Proxy Authentication
2+
3+
This guide explains how to configure MCP Gateway to work with authentication proxies like OAuth2 Proxy, Authelia, Cloudflare Access, or enterprise API gateways.
4+
5+
## Overview
6+
7+
When MCP Gateway is deployed behind an authentication proxy, you can disable its built-in JWT authentication and trust the proxy to handle user authentication. This is common in enterprise environments where authentication is centralized.
8+
9+
## Architecture
10+
11+
```
12+
User → Auth Proxy (OAuth/SAML) → MCP Gateway → MCP Servers
13+
14+
Identity Provider
15+
(Okta, Auth0, Azure AD)
16+
```
17+
18+
## Configuration
19+
20+
### Environment Variables
21+
22+
To enable proxy authentication, configure these environment variables:
23+
24+
```bash
25+
# Disable JWT authentication for MCP operations
26+
MCP_CLIENT_AUTH_ENABLED=false
27+
28+
# REQUIRED: Explicitly trust proxy authentication
29+
# Only set this when MCP Gateway is behind a trusted proxy!
30+
TRUST_PROXY_AUTH=true
31+
32+
# Header containing the authenticated username from proxy
33+
# Default: X-Authenticated-User
34+
PROXY_USER_HEADER=X-Authenticated-User
35+
36+
# Keep admin UI authentication enabled (optional)
37+
AUTH_REQUIRED=true
38+
```
39+
40+
### Security Warning
41+
42+
⚠️ **IMPORTANT**: Only disable MCP client authentication when MCP Gateway is deployed behind a trusted authentication proxy. Setting `MCP_CLIENT_AUTH_ENABLED=false` without `TRUST_PROXY_AUTH=true` will log a warning, as this removes a critical security layer.
43+
44+
## Common Proxy Configurations
45+
46+
### OAuth2 Proxy
47+
48+
OAuth2 Proxy is a popular reverse proxy that provides authentication using OAuth2 providers.
49+
50+
```yaml
51+
# docker-compose.yml
52+
services:
53+
oauth2-proxy:
54+
image: quay.io/oauth2-proxy/oauth2-proxy:latest
55+
ports:
56+
- "4180:4180"
57+
environment:
58+
OAUTH2_PROXY_CLIENT_ID: your-client-id
59+
OAUTH2_PROXY_CLIENT_SECRET: your-client-secret
60+
OAUTH2_PROXY_COOKIE_SECRET: your-cookie-secret
61+
OAUTH2_PROXY_UPSTREAMS: http://mcp-gateway:4444
62+
OAUTH2_PROXY_PASS_USER_HEADERS: true
63+
OAUTH2_PROXY_SET_XAUTHREQUEST: true
64+
65+
mcp-gateway:
66+
image: ghcr.io/contingentai/mcp-gateway:latest
67+
environment:
68+
MCP_CLIENT_AUTH_ENABLED: false
69+
TRUST_PROXY_AUTH: true
70+
PROXY_USER_HEADER: X-Auth-Request-User
71+
```
72+
73+
### Authelia
74+
75+
Authelia is a complete authentication and authorization server.
76+
77+
```yaml
78+
# Example Authelia forward auth configuration
79+
services:
80+
authelia:
81+
image: authelia/authelia
82+
volumes:
83+
- ./authelia:/config
84+
environment:
85+
TZ: America/New_York
86+
87+
mcp-gateway:
88+
image: ghcr.io/contingentai/mcp-gateway:latest
89+
environment:
90+
MCP_CLIENT_AUTH_ENABLED: false
91+
TRUST_PROXY_AUTH: true
92+
PROXY_USER_HEADER: Remote-User
93+
labels:
94+
- "traefik.http.routers.mcp.middlewares=authelia@docker"
95+
```
96+
97+
### Cloudflare Access
98+
99+
For Cloudflare Access, configure the gateway to read the authenticated user from Cloudflare's headers:
100+
101+
```bash
102+
MCP_CLIENT_AUTH_ENABLED=false
103+
TRUST_PROXY_AUTH=true
104+
PROXY_USER_HEADER=Cf-Access-Authenticated-User-Email
105+
```
106+
107+
### AWS API Gateway
108+
109+
When using AWS API Gateway with Lambda authorizers:
110+
111+
```bash
112+
MCP_CLIENT_AUTH_ENABLED=false
113+
TRUST_PROXY_AUTH=true
114+
PROXY_USER_HEADER=X-Authenticated-User
115+
```
116+
117+
Configure your Lambda authorizer to add the authenticated username to the context:
118+
119+
```python
120+
# Lambda authorizer example
121+
def lambda_handler(event, context):
122+
# Validate token...
123+
return {
124+
'principalId': user_id,
125+
'context': {
126+
'authenticatedUser': user_email
127+
}
128+
}
129+
```
130+
131+
## Header Passthrough
132+
133+
When using proxy authentication, you may want to pass additional headers to downstream MCP servers:
134+
135+
```bash
136+
# Enable header passthrough
137+
ENABLE_HEADER_PASSTHROUGH=true
138+
139+
# Headers to pass through (JSON array)
140+
DEFAULT_PASSTHROUGH_HEADERS='["X-Tenant-Id", "X-Request-Id", "X-Authenticated-User"]'
141+
```
142+
143+
## Kubernetes with Istio
144+
145+
In a service mesh with Istio, you can use JWT validation at the mesh level:
146+
147+
```yaml
148+
apiVersion: security.istio.io/v1beta1
149+
kind: RequestAuthentication
150+
metadata:
151+
name: mcp-gateway-auth
152+
spec:
153+
selector:
154+
matchLabels:
155+
app: mcp-gateway
156+
jwtRules:
157+
- issuer: "https://your-issuer.com"
158+
jwksUri: "https://your-issuer.com/.well-known/jwks.json"
159+
---
160+
apiVersion: v1
161+
kind: ConfigMap
162+
metadata:
163+
name: mcp-gateway-config
164+
data:
165+
MCP_CLIENT_AUTH_ENABLED: "false"
166+
TRUST_PROXY_AUTH: "true"
167+
PROXY_USER_HEADER: "X-User-Id"
168+
```
169+
170+
## Testing Proxy Authentication
171+
172+
To test your proxy authentication setup:
173+
174+
1. **Without proxy headers (should fail or return anonymous):**
175+
```bash
176+
curl http://localhost:4444/tools
177+
# Returns 401 or anonymous access depending on AUTH_REQUIRED
178+
```
179+
180+
2. **With proxy headers:**
181+
```bash
182+
curl -H "X-Authenticated-User: [email protected]" \
183+
http://localhost:4444/tools
184+
# Should return tools list for authenticated user
185+
```
186+
187+
3. **WebSocket with proxy auth:**
188+
```javascript
189+
const ws = new WebSocket('ws://localhost:4444/ws', {
190+
headers: {
191+
'X-Authenticated-User': '[email protected]'
192+
}
193+
});
194+
```
195+
196+
## Troubleshooting
197+
198+
### Warning: MCP auth disabled without trust
199+
200+
If you see this warning in logs:
201+
```
202+
WARNING - MCP client authentication is disabled but trust_proxy_auth is not set
203+
```
204+
205+
**Solution**: Set `TRUST_PROXY_AUTH=true` to acknowledge you're using proxy authentication.
206+
207+
### Authentication still required
208+
209+
**Problem**: Getting 401 errors even with proxy headers.
210+
211+
**Check**:
212+
1. Verify `MCP_CLIENT_AUTH_ENABLED=false`
213+
2. Ensure `TRUST_PROXY_AUTH=true`
214+
3. Confirm header name matches `PROXY_USER_HEADER`
215+
4. Check proxy is actually sending the header
216+
217+
### WebSocket connections fail
218+
219+
**Problem**: WebSocket connections are rejected.
220+
221+
**Solution**: Ensure your proxy passes headers to WebSocket upgrade requests. Some proxies require special configuration for WebSocket support.
222+
223+
## Migration from JWT Authentication
224+
225+
To migrate from JWT to proxy authentication:
226+
227+
1. **Deploy proxy** alongside existing setup
228+
2. **Test proxy** authentication with a subset of users
229+
3. **Update environment**:
230+
```bash
231+
MCP_CLIENT_AUTH_ENABLED=false
232+
TRUST_PROXY_AUTH=true
233+
PROXY_USER_HEADER=X-Authenticated-User
234+
```
235+
4. **Monitor logs** for authentication issues
236+
5. **Remove JWT** token generation once stable
237+
238+
## Security Best Practices
239+
240+
1. **Never expose MCP Gateway directly** when proxy auth is enabled
241+
2. **Use TLS** between proxy and gateway
242+
3. **Validate proxy certificates** in production
243+
4. **Monitor** authentication logs for anomalies
244+
5. **Implement rate limiting** at the proxy level
245+
6. **Use network policies** to ensure only the proxy can reach the gateway
246+
247+
## Example: Complete Setup with Traefik
248+
249+
```yaml
250+
# docker-compose.yml
251+
version: '3.8'
252+
253+
services:
254+
traefik:
255+
image: traefik:v2.10
256+
command:
257+
- "--providers.docker=true"
258+
- "--entrypoints.web.address=:80"
259+
ports:
260+
- "80:80"
261+
volumes:
262+
- /var/run/docker.sock:/var/run/docker.sock
263+
264+
oauth2-proxy:
265+
image: quay.io/oauth2-proxy/oauth2-proxy:latest
266+
environment:
267+
OAUTH2_PROXY_CLIENT_ID: ${CLIENT_ID}
268+
OAUTH2_PROXY_CLIENT_SECRET: ${CLIENT_SECRET}
269+
OAUTH2_PROXY_COOKIE_SECRET: ${COOKIE_SECRET}
270+
OAUTH2_PROXY_PROVIDER: google
271+
OAUTH2_PROXY_EMAIL_DOMAINS: "*"
272+
OAUTH2_PROXY_UPSTREAMS: "http://mcp-gateway:4444/"
273+
OAUTH2_PROXY_HTTP_ADDRESS: "0.0.0.0:4180"
274+
OAUTH2_PROXY_PASS_USER_HEADERS: "true"
275+
OAUTH2_PROXY_SET_XAUTHREQUEST: "true"
276+
labels:
277+
- "traefik.enable=true"
278+
- "traefik.http.routers.oauth2-proxy.rule=Host(`mcp.example.com`)"
279+
- "traefik.http.services.oauth2-proxy.loadbalancer.server.port=4180"
280+
281+
mcp-gateway:
282+
image: ghcr.io/contingentai/mcp-gateway:latest
283+
environment:
284+
MCP_CLIENT_AUTH_ENABLED: "false"
285+
TRUST_PROXY_AUTH: "true"
286+
PROXY_USER_HEADER: "X-Auth-Request-Email"
287+
AUTH_REQUIRED: "true" # Keep admin UI protected
288+
BASIC_AUTH_USER: ${ADMIN_USER}
289+
BASIC_AUTH_PASSWORD: ${ADMIN_PASSWORD}
290+
volumes:
291+
- ./data:/data
292+
```
293+
294+
This configuration provides Google OAuth authentication for all MCP Gateway endpoints while maintaining separate admin UI authentication.

0 commit comments

Comments
 (0)