Skip to main content

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_UUID> \
  --user-id <USER_UUID>

# 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_UUID>

# Update user
secure-mcp-gateway user update \
  --user-id <USER_UUID> \
  --email "[email protected]"

# Delete user
secure-mcp-gateway user delete --user-id <USER_UUID>
User Properties:
PropertyTypeDescription
User IDUUIDUnique identifier (auto-generated)
EmailstringUser email address
Created AtISO 8601User 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_UUID>

# List projects
secure-mcp-gateway project list

# Get project details
secure-mcp-gateway project get --project-id <PROJECT_UUID>

# Add user to project
secure-mcp-gateway project add-user \
  --project-id <PROJECT_UUID> \
  --user-id <USER_UUID>

# Remove project
secure-mcp-gateway project remove --project-id <PROJECT_UUID>
Project Properties:
PropertyTypeDescription
Project IDUUIDUnique identifier (auto-generated)
Project NamestringHuman-readable project name
MCP Config IDUUIDReference to mcp_configs entry
UsersarrayList of user UUIDs in this project
Created AtISO 8601Project 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"}'

Step 2: Gateway Extracts Credentials

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:
  1. Environment variables (stdio mode):
    • ENKRYPT_GATEWAY_KEY
    • ENKRYPT_PROJECT_ID (optional)
    • ENKRYPT_USER_ID (optional)
  2. HTTP headers (HTTP mode):
    • Authorization: Bearer <API_KEY>
    • X-Project-Id: <PROJECT_UUID> (optional)
    • X-User-Id: <USER_UUID> (optional)
  3. 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:
  1. Extract gateway_key from context
  2. Check if key exists in apikeys section
  3. If not found, return authentication error
  4. 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_UUID> \
  --user-id <USER_UUID> | jq -r '.api_key')

# Update client config with new key
# ...

# Disable old key
secure-mcp-gateway apikey disable --api-key <OLD_KEY>

# After verifying, delete old key
secure-mcp-gateway apikey delete --api-key <OLD_KEY>
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"
  }
}
For production environments, consider implementing additional authentication layers:
  1. Network-level: Use VPN or IP whitelisting
  2. TLS certificates: Enable mutual TLS (mTLS)
  3. 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_UUID> \
  --user-id <USER_UUID>

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_UUID>

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_UUID> \
  --user-id <USER_UUID>

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

Build docs developers (and LLMs) love