Documentation Index
Fetch the complete documentation index at: https://mcp-server-langgraph.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
68. Gateway-Level Authentication with Traefik ForwardAuth
Date: 2025-12-09
Status
Accepted
Category
Security
Context
Authentication in the MCP Server LangGraph stack was handled at the application level:
- Each service (MCP Server, Builder, Playground) independently validates JWT tokens from Keycloak
- Observability UIs (Grafana, Qdrant Dashboard, Traefik Dashboard) have no authentication
- This creates security gaps and duplicated authentication logic
Problems with Previous Approach
| Issue | Impact |
|---|
| Security Gap | Observability dashboards expose sensitive data without auth |
| Duplicated Logic | Each service implements JWT validation independently |
| Inconsistent UX | Some routes require auth, others don’t |
| No SSO | Users must authenticate separately per service |
Decision
Implement gateway-level authentication using Traefik’s ForwardAuth middleware with a dedicated authentication proxy service.
Architecture
┌─────────────────┐
│ Keycloak │
│ (OIDC IdP) │
└────────┬────────┘
│
│ OIDC
│
┌──────────┐ ┌─────────────┐ ┌───▼────────────┐
│ Client │────▶│ Traefik │────▶│ traefik- │
│ │ │ Gateway │ │ forward-auth │
└──────────┘ └──────┬──────┘ └───────┬────────┘
│ │
│ ForwardAuth │ Token
│ Middleware │ Validation
│ │
┌───────▼──────────────────────▼───────┐
│ │
┌──────────┼──────────┬──────────┬───────────────┐
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌─────────┐┌─────────┐┌─────────┐┌─────────┐ ┌──────────┐
│ MCP ││ Builder ││Playground││ Grafana │ │ Qdrant │
│ Server ││ ││ ││ │ │Dashboard │
└─────────┘└─────────┘└─────────┘└─────────┘ └──────────┘
Route Classification
| Category | Routes | Auth Required |
|---|
| Public | /authn/* (Keycloak), */health*, */ready* | No |
| Protected - Apps | /mcp/*, /build/*, /play/* | Yes |
| Protected - Observability | /dashboards/*, /telemetry/*, /gateway/* | Yes |
| Protected - Data | /authz/*, /vectors/*, /dashboard/* | Yes |
Implementation Components
1. traefik-forward-auth Service
Using thomseddon/traefik-forward-auth:
traefik-forward-auth:
image: thomseddon/traefik-forward-auth:2
environment:
- DEFAULT_PROVIDER=oidc
- PROVIDERS_OIDC_ISSUER_URL=http://keycloak-test:8080/authn/realms/master
- PROVIDERS_OIDC_CLIENT_ID=mcp-server
- PROVIDERS_OIDC_CLIENT_SECRET=test-client-secret-for-e2e-tests
- SECRET=random-secret-for-cookie-signing
- COOKIE_DOMAIN=localhost
- INSECURE_COOKIE=true # For local dev (no HTTPS)
labels:
- "traefik.http.middlewares.forward-auth.forwardauth.address=http://traefik-forward-auth:4181"
- "traefik.http.middlewares.forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User,X-Auth-User"
2. Traefik Middleware Configuration
Apply middleware to protected routes:
# Protected service example
builder-test:
labels:
- "traefik.http.routers.builder.middlewares=forward-auth@docker,builder-strip"
3. Public Route Bypass
Health/readiness endpoints bypass auth by not including the forward-auth middleware.
Protected Routes Summary
| Route | Service | Middleware Chain |
|---|
/gateway | Traefik Dashboard | forward-auth@docker,gateway-rewrite |
/authz | OpenFGA API | forward-auth@docker,openfga-strip |
/vectors | Qdrant API | forward-auth@docker,qdrant-strip |
/dashboard | Qdrant Dashboard | forward-auth@docker |
/mcp | MCP Server API | forward-auth@docker,mcp-strip |
/dashboards | Grafana | forward-auth@docker |
/telemetry | Alloy | forward-auth@docker,alloy-strip |
/build | Builder | forward-auth@docker,builder-strip |
/play | MCP Playground | forward-auth@docker,playground-strip |
Test Users
Pre-configured users in Keycloak test realm:
| User | Password | Email |
|---|
admin | admin | - |
alice | alice123 | alice@example.com |
bob | bob123 | bob@example.com |
Consequences
Positive
- Centralized Authentication: Single point of auth enforcement
- Consistent Security: All protected routes use same auth flow
- SSO Experience: One login works across all services
- Reduced Code: Remove JWT validation from individual services
- Observability Protection: Grafana, Qdrant UI now protected
Negative
- Additional Service: traefik-forward-auth adds complexity
- Single Point of Failure: Auth proxy down = all protected routes fail
- Cookie-Based: Session management adds state
- Local Dev Complexity: Need to handle auth in development
Neutral
- Migration Required: Existing services need middleware configuration
- Testing Changes: Integration tests need auth awareness
Alternatives Considered
1. OAuth2 Proxy
More feature-rich but heavier weight. Better for complex scenarios.
2. Application-Level Only
Current approach. Simple but duplicates logic and leaves gaps.
3. Keycloak Gatekeeper
Deprecated (louketo-proxy). Not recommended.
4. Kong/Ambassador
Full API gateway. Overkill for test infrastructure.
Files Changed
docker-compose.test.yml - Added traefik-forward-auth service and middleware
tests/integration/gateway/test_traefik_auth_middleware.py - Integration tests
adr/adr-0068-gateway-level-authentication.md - This ADR
References