Authentication Overview
The Secure MCP Gateway uses a multi-layered authentication system that maps API keys to projects and users, ensuring secure access control and proper request routing.
Authentication Architecture
┌──────────────┐
│ MCP Client │
└──────┬───────┘
│ API Key in request context
▼
┌──────────────────────────────────┐
│ Gateway Server (gateway.py) │
│ Extract credentials from ctx │
└──────┬───────────────────────────┘
│
▼
┌──────────────────────────────────┐
│ Auth Plugin (config_manager.py) │
├──────────────────────────────────┤
│ 1. Validate API key exists │
│ 2. Lookup in apikeys section │
│ 3. Get project_id & user_id │
│ 4. Get mcp_config_id from │
│ project │
│ 5. Load gateway config │
└──────┬───────────────────────────┘
│
▼
┌──────────────────────────────────┐
│ Authenticated Request │
│ - gateway_key: "abc123..." │
│ - project_id: "uuid-1234" │
│ - user_id: "uuid-5678" │
│ - mcp_config_id: "uuid-abcd" │
│ - gateway_config: {...} │
└──────────────────────────────────┘
Core Concepts
1. API Keys (Gateway Keys)
Purpose: Authenticate clients and identify their project and user context.
Location in config:
{
"apikeys" : {
"YOUR_GATEWAY_API_KEY" : {
"project_id" : "PROJECT_UUID" ,
"user_id" : "USER_UUID" ,
"created_at" : "2025-01-01T00:00:00.000000"
}
}
}
API Key Format:
34+ characters
URL-safe characters (alphanumeric, _, -)
Generated by secure_mcp_gateway.utils.generate_custom_id()
Example: 2W8UupCkazk4SsOcSu_1hAbiOgPdv0g-nN9NtfZyg-rvYGat
Generation:
# Generate new API key
secure-mcp-gateway apikey generate \
--project-id < PROJECT_UUI D > \
--user-id < USER_UUI D >
# Output:
# {
# "api_key": "NEW_GENERATED_KEY",
# "project_id": "PROJECT_UUID",
# "user_id": "USER_UUID",
# "created_at": "2025-01-15T10:30:00.123456"
# }
API keys are automatically generated when you run secure-mcp-gateway generate-config.
2. Users
Purpose: Represent individual users of the gateway.
Location in config:
{
"users" : {
"USER_UUID" : {
"email" : "[email protected] " ,
"created_at" : "2025-01-01T00:00:00.000000"
}
}
}
User Management:
# Create user
secure-mcp-gateway user create \
--email "[email protected] "
# List users
secure-mcp-gateway user list
# Get user details
secure-mcp-gateway user get --user-id < USER_UUI D >
# Update user
secure-mcp-gateway user update \
--user-id < USER_UUI D > \
--email "[email protected] "
# Delete user
secure-mcp-gateway user delete --user-id < USER_UUI D >
User Properties:
Property Type Description User ID UUID Unique identifier (auto-generated) Email string User email address Created At ISO 8601 User creation timestamp
3. Projects
Purpose: Group users with a shared MCP configuration. Multiple users can belong to the same project and share access to the same set of MCP servers.
Location in config:
{
"projects" : {
"PROJECT_UUID" : {
"project_name" : "Production Environment" ,
"mcp_config_id" : "MCP_CONFIG_UUID" ,
"users" : [ "USER_UUID_1" , "USER_UUID_2" ],
"created_at" : "2025-01-01T00:00:00.000000"
}
}
}
Project Management:
# Create project
secure-mcp-gateway project create \
--name "Production Environment" \
--config-id < MCP_CONFIG_UUI D >
# List projects
secure-mcp-gateway project list
# Get project details
secure-mcp-gateway project get --project-id < PROJECT_UUI D >
# Add user to project
secure-mcp-gateway project add-user \
--project-id < PROJECT_UUI D > \
--user-id < USER_UUI D >
# Remove project
secure-mcp-gateway project remove --project-id < PROJECT_UUI D >
Project Properties:
Property Type Description Project ID UUID Unique identifier (auto-generated) Project Name string Human-readable project name MCP Config ID UUID Reference to mcp_configs entry Users array List of user UUIDs in this project Created At ISO 8601 Project creation timestamp
4. MCP Configs
Purpose: Define the set of MCP servers, their configurations, and guardrail policies.
Location in config:
{
"mcp_configs" : {
"MCP_CONFIG_UUID" : {
"mcp_config_name" : "production_config" ,
"mcp_config" : [
{
"server_name" : "github_server" ,
"config" : { ... },
"tools" : { ... },
"input_guardrails_policy" : { ... },
"output_guardrails_policy" : { ... }
}
]
}
}
}
See Configuration for complete MCP config structure.
Authentication Flow
Step 1: Client Provides API Key
stdio mode (Claude Desktop, Cursor):
{
"mcpServers" : {
"Enkrypt Secure MCP Gateway" : {
"command" : "mcp" ,
"args" : [ "run" , "/path/to/gateway.py" ],
"env" : {
"ENKRYPT_GATEWAY_KEY" : "YOUR_API_KEY" ,
"ENKRYPT_PROJECT_ID" : "PROJECT_UUID" ,
"ENKRYPT_USER_ID" : "USER_UUID"
}
}
}
}
HTTP mode:
curl -X POST http://gateway:8000/mcp/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"method": "tools/list"}'
Location: src/secure_mcp_gateway/gateway.py:253
def get_gateway_credentials ( ctx : Context):
"""Extract credentials from request context."""
auth_manager = get_auth_config_manager()
return auth_manager.get_gateway_credentials(ctx)
# Returns:
# {
# "gateway_key": "YOUR_API_KEY",
# "project_id": "PROJECT_UUID",
# "user_id": "USER_UUID"
# }
Extraction sources:
Environment variables (stdio mode):
ENKRYPT_GATEWAY_KEY
ENKRYPT_PROJECT_ID (optional)
ENKRYPT_USER_ID (optional)
HTTP headers (HTTP mode):
Authorization: Bearer <API_KEY>
X-Project-Id: <PROJECT_UUID> (optional)
X-User-Id: <USER_UUID> (optional)
Request context (FastMCP):
ctx.request_context.request.headers
Step 3: Validate API Key
Location: src/secure_mcp_gateway/plugins/auth/config_manager.py
auth_manager = get_auth_config_manager()
auth_result = await auth_manager.authenticate(ctx)
if not auth_result[ "authenticated" ]:
return {
"status" : "error" ,
"error" : "Invalid API key" ,
"message" : "Authentication failed"
}
Validation process:
Extract gateway_key from context
Check if key exists in apikeys section
If not found, return authentication error
If found, retrieve project_id and user_id
Step 4: Resolve Project and User
# Get API key entry
apikey_entry = config[ "apikeys" ].get(gateway_key)
if not apikey_entry:
raise AuthenticationError( "Invalid API key" )
# Get project and user IDs
project_id = apikey_entry[ "project_id" ]
user_id = apikey_entry[ "user_id" ]
# Get project entry
project = config[ "projects" ].get(project_id)
if not project:
raise AuthenticationError( "Project not found" )
# Get user entry
user = config[ "users" ].get(user_id)
if not user:
raise AuthenticationError( "User not found" )
# Verify user belongs to project
if user_id not in project[ "users" ]:
raise AuthenticationError( "User not authorized for project" )
Step 5: Load MCP Configuration
# Get MCP config ID from project
mcp_config_id = project[ "mcp_config_id" ]
# Get MCP config entry
mcp_config = config[ "mcp_configs" ].get(mcp_config_id)
if not mcp_config:
raise AuthenticationError( "MCP configuration not found" )
# Return gateway config
gateway_config = {
"project_id" : project_id,
"project_name" : project[ "project_name" ],
"user_id" : user_id,
"email" : user[ "email" ],
"mcp_config_id" : mcp_config_id,
"mcp_config" : mcp_config[ "mcp_config" ]
}
Step 6: Cache Configuration
Location: src/secure_mcp_gateway/client.py:667
# Cache gateway config for faster lookups
session_key = f " { gateway_key } _ { project_id } _ { user_id } _ { mcp_config_id } "
cache_gateway_config(cache_client, session_key, gateway_config)
# Cache expires after 24 hours (default)
Admin API Authentication
Purpose: Secure REST API endpoints for administrative operations.
Admin API Key:
{
"admin_apikey" : "256-CHARACTER-RANDOM-STRING"
}
Usage:
curl -X GET http://localhost:8001/api/v1/configs \
-H "Authorization: Bearer YOUR_ADMIN_API_KEY"
Protected endpoints:
/api/v1/configs/* - Configuration management
/api/v1/projects/* - Project management
/api/v1/users/* - User management
/api/v1/api-keys/* - API key management
/api/v1/system/* - System operations
Public endpoints:
/health - Health check (no auth required)
/docs - Swagger documentation (no auth required)
Security Best Practices
Rotate API keys regularly to minimize exposure: # Generate new key
NEW_KEY = $( secure-mcp-gateway apikey generate \
--project-id < PROJECT_UUI D > \
--user-id < USER_UUI D > | jq -r '.api_key' )
# Update client config with new key
# ...
# Disable old key
secure-mcp-gateway apikey disable --api-key < OLD_KE Y >
# After verifying, delete old key
secure-mcp-gateway apikey delete --api-key < OLD_KE Y >
Least Privilege Principle
Create separate projects for different access levels: {
"projects" : {
"readonly_project" : {
"mcp_config_id" : "readonly_config" ,
"users" : [ "contractor_user" ]
},
"admin_project" : {
"mcp_config_id" : "full_access_config" ,
"users" : [ "admin_user" ]
}
}
}
Enable telemetry to track all authentication attempts: {
"plugins" : {
"telemetry" : {
"provider" : "opentelemetry" ,
"config" : {
"enabled" : true ,
"url" : "http://otel-collector:4317"
}
}
}
}
Review logs regularly: # Query authentication failures in Grafana/Loki
{job="secure-mcp-gateway"} |= "Authentication failed"
Never hardcode API keys in code or commit them to version control: Good: # Store in environment variable
export ENKRYPT_GATEWAY_KEY = $( cat ~/.secrets/gateway_key )
# Or use secret management
export ENKRYPT_GATEWAY_KEY = $( aws secretsmanager get-secret-value \
--secret-id gateway-api-key --query SecretString --output text )
Bad: // claude_desktop_config.json - DO NOT DO THIS
{
"env" : {
"ENKRYPT_GATEWAY_KEY" : "hardcoded-key-12345"
}
}
Multi-Factor Authentication
For production environments, consider implementing additional authentication layers:
Network-level: Use VPN or IP whitelisting
TLS certificates: Enable mutual TLS (mTLS)
OAuth integration: Use Enkrypt’s OAuth provider for centralized auth
Example with OAuth: {
"plugins" : {
"auth" : {
"provider" : "enkrypt" ,
"config" : {
"api_key" : "YOUR_ENKRYPT_API_KEY" ,
"base_url" : "https://api.enkryptai.com" ,
"require_mfa" : true
}
}
}
}
Common Scenarios
Scenario 1: Single User, Single Project
Use case: Personal development environment
{
"users" : {
"user-001" : {
"email" : "[email protected] " ,
"created_at" : "2025-01-01T00:00:00"
}
},
"projects" : {
"project-dev" : {
"project_name" : "Development" ,
"mcp_config_id" : "config-dev" ,
"users" : [ "user-001" ],
"created_at" : "2025-01-01T00:00:00"
}
},
"apikeys" : {
"dev-api-key-12345" : {
"project_id" : "project-dev" ,
"user_id" : "user-001" ,
"created_at" : "2025-01-01T00:00:00"
}
}
}
Scenario 2: Team Project, Multiple Users
Use case: Shared production environment
{
"users" : {
"user-001" : { "email" : "[email protected] " , ... },
"user-002" : { "email" : "[email protected] " , ... },
"user-003" : { "email" : "[email protected] " , ... }
},
"projects" : {
"project-prod" : {
"project_name" : "Production" ,
"mcp_config_id" : "config-prod" ,
"users" : [ "user-001" , "user-002" , "user-003" ],
"created_at" : "2025-01-01T00:00:00"
}
},
"apikeys" : {
"alice-prod-key" : {
"project_id" : "project-prod" ,
"user_id" : "user-001" ,
...
},
"bob-prod-key" : {
"project_id" : "project-prod" ,
"user_id" : "user-002" ,
...
},
"charlie-prod-key" : {
"project_id" : "project-prod" ,
"user_id" : "user-003" ,
...
}
}
}
All three users share the same MCP config but have individual API keys for tracking.
Scenario 3: Multi-Environment, Same User
Use case: One user accessing dev, staging, and production
{
"users" : {
"user-001" : { "email" : "[email protected] " , ... }
},
"projects" : {
"project-dev" : {
"project_name" : "Development" ,
"mcp_config_id" : "config-dev" ,
"users" : [ "user-001" ],
...
},
"project-staging" : {
"project_name" : "Staging" ,
"mcp_config_id" : "config-staging" ,
"users" : [ "user-001" ],
...
},
"project-prod" : {
"project_name" : "Production" ,
"mcp_config_id" : "config-prod" ,
"users" : [ "user-001" ],
...
}
},
"apikeys" : {
"dev-key-12345" : { "project_id" : "project-dev" , "user_id" : "user-001" , ... },
"staging-key-67890" : { "project_id" : "project-staging" , "user_id" : "user-001" , ... },
"prod-key-abcde" : { "project_id" : "project-prod" , "user_id" : "user-001" , ... }
}
}
The user has different API keys for each environment.
Scenario 4: Service Accounts
Use case: Automated tools/CI/CD accessing the gateway
{
"users" : {
"service-ci-cd" : {
"email" : "[email protected] " ,
"created_at" : "2025-01-01T00:00:00"
},
"service-monitoring" : {
"email" : "[email protected] " ,
"created_at" : "2025-01-01T00:00:00"
}
},
"projects" : {
"project-automation" : {
"project_name" : "Automation" ,
"mcp_config_id" : "config-readonly" ,
"users" : [ "service-ci-cd" , "service-monitoring" ],
"created_at" : "2025-01-01T00:00:00"
}
},
"apikeys" : {
"ci-cd-key-12345" : {
"project_id" : "project-automation" ,
"user_id" : "service-ci-cd" ,
...
},
"monitoring-key-67890" : {
"project_id" : "project-automation" ,
"user_id" : "service-monitoring" ,
...
}
}
}
Troubleshooting
Error: “Invalid API key”
Cause: API key not found in apikeys section.
Solution:
# List all API keys
secure-mcp-gateway apikey list
# Generate new key if needed
secure-mcp-gateway apikey generate \
--project-id < PROJECT_UUI D > \
--user-id < USER_UUI D >
Error: “Project not found”
Cause: project_id referenced by API key doesn’t exist.
Solution:
# List all projects
secure-mcp-gateway project list
# Create missing project
secure-mcp-gateway project create \
--name "My Project" \
--config-id < MCP_CONFIG_UUI D >
Error: “User not authorized for project”
Cause: User exists but is not in project’s user list.
Solution:
# Add user to project
secure-mcp-gateway project add-user \
--project-id < PROJECT_UUI D > \
--user-id < USER_UUI D >
Error: “MCP configuration not found”
Cause: mcp_config_id referenced by project doesn’t exist.
Solution:
# List all configs
secure-mcp-gateway config list
# Create missing config
secure-mcp-gateway config add \
--name "My Config"
Next Steps
Configuration Learn about MCP configs and server settings
API Keys Management CLI commands for managing API keys
Projects CLI commands for managing projects
Users CLI commands for managing users