MCP Gateway for external Authentication and Authorization
Documentation
MCPAuth: Gateway Authentication for Secure Enterprise MCP Integrations
McpAuth is the authentication and authorization component of the MCP Gateway Proof of Concept (PoC) described in the paper:
*Simplified and Secure MCP Gateways for Enterprise AI Integration*
Ivo Brett, CISSP, B.Eng, MSc
View Paper (2025)
This repository is part of a broader initiative to enable secure, scalable, and compliant enterprise integration with the Model Context Protocol (MCP). See the website SelfHostedMCP.com. It provides an extensible OAuth2.1-based authentication gateway that offloads identity, authorization, and policy management from backend MCP servers—ensuring conformance with the 2025-03-26 MCP Specification.
---
Purpose
McpAuth is designed to:
- Decouple security logic from MCP servers
- Centralize identity management using OAuth 2.1 & OIDC
- Support dynamic client registration
- Enforce fine-grained token scopes and policy controls
- Act as a composable module in enterprise-grade Zero Trust architectures
---
Background
This implementation is part of a larger PoC that validates:
- A reference MCP Gateway architecture for secure deployments
- Threat model mapping aligned with frameworks such as MAESTRO and Narajala & Habler
- Real-world compatibility with tools like Cloudflare Tunnels, WireGuard, Traefik, and CrowdSec
The full proof of concept includes:
- Two isolated MCP servers (local and cloud-based)
- Secure tunneling via WireGuard and Pangolin
- Centralized intrusion detection and observability
- Seamless integration with Anthropic's MCP Inspector
Features
- OAuth2 authentication with PKCE via Traefik
forwardAuth - Seamless integration with MCP Gateway SSE endpoints
- Email whitelisting for controlled access
- Docker-ready, easy to deploy
- Includes a Python-based test server
---
Quick Start (assuming a completely standalone working environment)
Set Up Google OAuth
Go to the Google Cloud Console
Navigate to APIs & Services > Credentials
Click Create Credentials → OAuth client ID
Choose Web Application
Add an Authorized redirect URI — you’ll get this later when you set up Traefik, but it will look like:
https://oauth.yourdomain.com/callback
Save the Client ID and Client Secret for later use.
Create .env file
CLIENT_ID=
CLIENT_SECRET=🔧 Note the Configuration Flags
Use flags or environment variables:
| Variable | Default | Description |
|---|---|---|
PORT | 11000 | Port for the auth server |
PROTECTED_PATH | /sse | Protected endpoint path |
OAUTH_DOMAIN | *(none)* | OAuth issuer domain |
CLIENT_ID | *(none)* | OAuth client ID |
CLIENT_SECRET | *(none)* | OAuth client secret |
ALLOWED_EMAILS | *(none)* | Comma-separated list of allowed emails |
LOG_LEVEL | 1 | 0=debug, 1=info, 2=minimal |
Scope Configuration
MCPAuth supports fine-grained scope control to enhance security by limiting token privileges. You can define which scopes are allowed in an OAuth request and which are required for a token to be considered valid.
- Allowed Scopes: A whitelist of scopes that the middleware is permitted to request from the OAuth provider. If a client requests scopes not in this list, they will be ignored.
- Required Scopes: A list of scopes that *must* be present in the granted token after the user authenticates. If the token does not contain all of these scopes, access will be denied with a
403 Forbidden (Insufficient Scope)error.
This allows you to enforce policies like requiring an email scope for all users while allowing clients to optionally request additional permissions like profile or custom API scopes.
Configuration
You can configure scopes using command-line flags or environment variables:
| Variable | Flag | Description |
|---|---|---|
ALLOWED_SCOPES | -allowedScopes | Comma-separated list of allowed OAuth scopes. |
REQUIRED_SCOPES | -requiredScopes | Comma-separated list of required OAuth scopes. |
Example:
To allow clients to request openid, email, and profile scopes, but require that all valid tokens include at least openid and email, you would set:
ALLOWED_SCOPES=openid,email,profileREQUIRED_SCOPES=openid,email
Docker Compose
services:
mcpauth:
image: oideibrett/mcpauth:latest
environment:
- PORT=11000
- CLIENT_ID=${CLIENT_ID}
- CLIENT_SECRET=${CLIENT_SECRET}
ports:
- "11000:11000"
traefik:
image: traefik::v3.4.1
command:
- "--providers.docker=true"
- "--entrypoints.websecure.address=:443"
ports:
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sockDevelopers Installation
Prerequisites
- Go 1.21+
- Traefik v2.x+
- An OAuth provider (e.g., Google, GitHub)
Installation
git clone https://github.com/oidebrett/mcpauth
cd mcpauth
go mod tidygo run cmd/main.go -port=11000 -oauthDomain=your-domain.com---
Docker Deployment
Docker build
docker buildx build --platform linux/amd64,linux/arm64 -t oideibrett/mcpauth:dev --push .Basic Docker Compose
services:
mcpauth:
build: .
environment:
- PORT=11000
- CLIENT_ID=${CLIENT_ID}
- CLIENT_SECRET=${CLIENT_SECRET}
ports:
- "11000:11000"---
Traefik Integration
ForwardAuth Middleware
http:
middlewares:
mcp-auth:
forwardAuth:
address: "http://mcpauth:11000/auth"
authResponseHeaders:
- "X-Forwarded-User"Attach to a Router
labels:
- "traefik.http.routers.myapp.middlewares=mcp-auth@file"---
Testing
Run Included Test Server
cd test_mcp_server
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python mcp-server-sse.pyWith curl
Here are a few curl commands to test different authentication and authorization scenarios.
1. Health Check
This command checks if the mcpauth service is running and responsive. You should receive a 200 OK response.
curl -i http://localhost:11000/health2. Accessing a Protected Endpoint (No Token)
When you try to access a protected endpoint like /sse without a valid token, mcpauth should initiate the OAuth2 authentication flow. For a non-browser client like curl, this will result in a 302 Found redirect to the Google login page.
curl -i http://localhost:11000/sse*Expected Output:* An HTTP 302 Found redirecting to `https://accounts.google.com/...
3. Accessing a Protected Endpoint (Valid Token)
Once you have a valid bearer token from the OAuth provider, you can use it to access the protected endpoint. This request should be successful (200 OK), and mcpauth will forward the request to the upstream service.
# Replace YOUR_VALID_TOKEN with an actual bearer token
curl -i -H "Authorization: Bearer YOUR_VALID_TOKEN" http://localhost:11000/sse*Expected Output:* An HTTP 200 OK and the response from the test server (e.g., the SSE stream).
4. Accessing a Protected Endpoint (Invalid/Expired Token)
If you use a token that is invalid, malformed, or expired, mcpauth should deny access. This will likely result in a 401 Unauthorized error, prompting for re-authentication.
curl -i -H "Authorization: Bearer INVALID_TOKEN" http://localhost:11000/sse*Expected Output:* An HTTP 401 Unauthorized response.
5. Accessing with a Token from an Unauthorized User
If the ALLOWED_EMAILS list is configured, mcpauth will validate the user's email from the token. If the user is not on the whitelist, access will be denied.
# Use a valid token from a user whose email is NOT in ALLOWED_EMAILS
curl -i -H "Authorization: Bearer TOKEN_FROM_UNAUTHORIZED_USER" http://localhost:11000/sse*Expected Output:* An HTTP 403 Forbidden response.
---
Middleware Chain (Traefik)
Apply middlewares in this order:
1. mcp-cors-headers
2. redirect-regex
3. mcp-auth
Example dynamic config:
http:
middlewares:
mcp-cors-headers:
headers:
accessControlAllowCredentials: true
accessControlAllowHeaders:
- Authorization
- Content-Type
- mcp-protocol-version
accessControlAllowMethods:
- GET
- POST
- OPTIONS
accessControlAllowOriginList:
- "*"
accessControlMaxAge: 86400
addVaryHeader: true
redirect-regex:
redirectRegex:
regex: "^https://([a-z0-9-]+)\.(.+)/\.well-known/(.+)"
replacement: "https://oauth.${2}/.well-known/${3}"
permanent: true
mcp-auth:
forwardAuth:
address: "http://mcpauth:11000/sse"
authResponseHeaders:
- X-Forwarded-User---
Middleware Manager Support
This project supports middleware-manager.
Example templates.yml:
middlewares:
- id: mcp-auth
name: MCP Authentication
type: forwardAuth
config:
address: "http://mcpauth:11000/sse"
authResponseHeaders:
- "X-Forwarded-User"
- id: mcp-cors-headers
name: MCP CORS Headers
type: headers
config:
accessControlAllowMethods:
- GET
- POST
- OPTIONS
accessControlAllowOriginList:
- "*"
accessControlAllowHeaders:
- Authorization
- Content-Type
- mcp-protocol-version
accessControlMaxAge: 86400
accessControlAllowCredentials: true
addVaryHeader: true
- id: redirect-regex
name: Regex Redirect
type: redirectregex
config:
regex: "^https://([a-z0-9-]+)\.yourdomain\.com/\.well-known/oauth-authorization-server"
replacement: "https://oauth.yourdomain.com/.well-known/oauth-authorization-server"
permanent: true---
License
Licensed under the GNU General Public License v3.0.
Similar MCP
Based on tags & features
Trending MCP
Most active this week