Overview
API key endpoints allow you to manage user API keys used for gateway authentication. User API keys are distinct from the admin API key - they grant users access to the MCP gateway within specific projects, while the admin API key is used for REST API management.
API Key Types
Understanding the difference between admin and user API keys is critical:
Feature Admin API Key User API Keys Purpose REST API management Gateway MCP access Scope Full system access Project-specific Format Custom format gw_ prefix + 36 charactersStorage admin_apikey fieldapikeys sectionManagement Manual regeneration Via API endpoints Usage Authorization: Bearer headerMCP client request context
List All API Keys
Retrieve all user API keys across the entire system.
curl -X GET "http://localhost:8001/api/v1/api-keys" \
-H "Authorization: Bearer ${ ADMIN_KEY }"
Response: 200 OK
{
"message" : "All API keys retrieved successfully" ,
"data" : [
{
"api_key" : "gw_abc123xyz789def456uvw012pqr345stu678" ,
"user_id" : "440e8400-e29b-41d4-a716-446655440000" ,
"user_email" : "[email protected] " ,
"project_id" : "660e8400-e29b-41d4-a716-446655440000" ,
"project_name" : "development-project" ,
"created_at" : "2024-01-01T12:00:00.000000" ,
"status" : "active"
},
{
"api_key" : "gw_def456uvw012pqr345stu678abc123xyz789" ,
"user_id" : "330e8400-e29b-41d4-a716-446655440000" ,
"user_email" : "[email protected] " ,
"project_id" : "770e8400-e29b-41d4-a716-446655440000" ,
"project_name" : "production-project" ,
"created_at" : "2024-01-02T12:00:00.000000" ,
"status" : "active"
}
],
"timestamp" : "2024-01-01T12:00:00.000000"
}
The actual API key (prefixed with gw_)
ID of the user who owns this key
Email of the user who owns this key
ID of the project this key grants access to
Name of the project this key grants access to
ISO 8601 timestamp of key creation
Key status: active, disabled, or revoked
Get API Key Details
Retrieve details for a specific API key.
curl -X GET "http://localhost:8001/api/v1/api-keys/{api_key}" \
-H "Authorization: Bearer ${ ADMIN_KEY }"
The API key to retrieve (starts with gw_)
Response: 200 OK
{
"message" : "API key details retrieved successfully" ,
"data" : {
"api_key" : "gw_abc123xyz789def456uvw012pqr345stu678" ,
"user_id" : "440e8400-e29b-41d4-a716-446655440000" ,
"user_email" : "[email protected] " ,
"project_id" : "660e8400-e29b-41d4-a716-446655440000" ,
"project_name" : "development-project" ,
"mcp_config_id" : "550e8400-e29b-41d4-a716-446655440000" ,
"mcp_config_name" : "dev-config" ,
"created_at" : "2024-01-01T12:00:00.000000" ,
"status" : "active" ,
"last_used" : "2024-01-15T14:30:00.000000"
},
"timestamp" : "2024-01-01T12:00:00.000000"
}
Error Response: 404 Not Found
{
"error" : "API key not found" ,
"detail" : "No API key found with the provided identifier" ,
"timestamp" : "2024-01-01T12:00:00.000000"
}
Rotate API Key
Rotate (replace) an existing API key with a new one.
Rotation generates a new API key while immediately invalidating the old one. Use this for security incidents or regular key rotation policies.
curl -X POST "http://localhost:8001/api/v1/api-keys/rotate" \
-H "Authorization: Bearer ${ ADMIN_KEY }" \
-H "Content-Type: application/json" \
-d '{"api_key": "gw_old_key_to_rotate"}'
The existing API key to rotate (will be invalidated)
Response: 200 OK
{
"message" : "API key rotated successfully" ,
"data" : {
"new_api_key" : "gw_xyz789def456uvw012pqr345stu678abc123" ,
"old_api_key" : "gw_old_key_to_rotate" ,
"status" : "active"
},
"timestamp" : "2024-01-01T12:00:00.000000"
}
The old API key is immediately invalidated. Ensure you update all clients using the old key.
Disable API Key
Temporarily disable an API key without deleting it.
curl -X POST "http://localhost:8001/api/v1/api-keys/{api_key}/disable" \
-H "Authorization: Bearer ${ ADMIN_KEY }"
Response: 200 OK
{
"message" : "API key disabled successfully" ,
"timestamp" : "2024-01-01T12:00:00.000000"
}
Disabled keys can be re-enabled using the enable endpoint. This is useful for temporary access suspension.
Enable API Key
Re-enable a previously disabled API key.
curl -X POST "http://localhost:8001/api/v1/api-keys/{api_key}/enable" \
-H "Authorization: Bearer ${ ADMIN_KEY }"
Response: 200 OK
{
"message" : "API key enabled successfully" ,
"timestamp" : "2024-01-01T12:00:00.000000"
}
Delete API Key
Permanently delete an API key.
Deleted API keys cannot be recovered. Consider using disable instead for temporary suspension.
curl -X DELETE "http://localhost:8001/api/v1/api-keys/{api_key}" \
-H "Authorization: Bearer ${ ADMIN_KEY }"
Response: 200 OK
{
"message" : "API key deleted successfully" ,
"timestamp" : "2024-01-01T12:00:00.000000"
}
API Key Lifecycle Management
Key Rotation Strategy
Implement automated key rotation for enhanced security:
import requests
from datetime import datetime, timedelta
class APIKeyManager :
def __init__ ( self , base_url , admin_key ):
self .base_url = base_url
self .headers = {
"Authorization" : f "Bearer { admin_key } " ,
"Content-Type" : "application/json"
}
def should_rotate ( self , api_key_details , max_age_days = 90 ):
"""Check if key should be rotated based on age"""
created_at = datetime.fromisoformat(
api_key_details[ 'created_at' ].replace( 'Z' , '+00:00' )
)
age = datetime.now() - created_at
return age > timedelta( days = max_age_days)
def rotate_old_keys ( self , max_age_days = 90 ):
"""Rotate all keys older than specified days"""
# Get all keys
response = requests.get(
f " { self .base_url } /api-keys" ,
headers = self .headers
)
all_keys = response.json()[ "data" ]
rotated = []
for key_info in all_keys:
if self .should_rotate(key_info, max_age_days):
# Rotate the key
rotate_response = requests.post(
f " { self .base_url } /api-keys/rotate" ,
headers = self .headers,
json = { "api_key" : key_info[ "api_key" ]}
)
if rotate_response.status_code == 200 :
new_key = rotate_response.json()[ "data" ][ "new_api_key" ]
rotated.append({
"user" : key_info[ "user_email" ],
"old_key" : key_info[ "api_key" ],
"new_key" : new_key
})
return rotated
# Usage
manager = APIKeyManager(
base_url = "http://localhost:8001/api/v1" ,
admin_key = "your-admin-key"
)
# Rotate all keys older than 90 days
rotated_keys = manager.rotate_old_keys( max_age_days = 90 )
for rotation in rotated_keys:
print ( f "Rotated key for { rotation[ 'user' ] } " )
print ( f " Old: { rotation[ 'old_key' ][: 20 ] } ..." )
print ( f " New: { rotation[ 'new_key' ][: 20 ] } ..." )
Access Control Patterns
Temporary Access
Grant temporary access by enabling/disabling keys:
import time
from threading import Timer
def grant_temporary_access ( api_key , duration_hours = 24 ):
"""Enable a key for a specific duration"""
# Enable the key
requests.post(
f "http://localhost:8001/api/v1/api-keys/ { api_key } /enable" ,
headers = { "Authorization" : f "Bearer { admin_key } " }
)
print ( f "Access granted for { duration_hours } hours" )
# Schedule automatic disable
def auto_disable ():
requests.post(
f "http://localhost:8001/api/v1/api-keys/ { api_key } /disable" ,
headers = { "Authorization" : f "Bearer { admin_key } " }
)
print ( f "Access automatically revoked for { api_key } " )
timer = Timer(duration_hours * 3600 , auto_disable)
timer.start()
# Grant 24-hour access
grant_temporary_access( "gw_temporary_key" , duration_hours = 24 )
Emergency Key Revocation
Quickly revoke all keys for a compromised user:
def emergency_revoke_user_keys ( user_email ):
"""Revoke all API keys for a user"""
# Get user's API keys
response = requests.get(
f "http://localhost:8001/api/v1/users/ { user_email } /api-keys" ,
headers = { "Authorization" : f "Bearer { admin_key } " }
)
keys = response.json()[ "data" ]
for key_info in keys:
# Delete each key
requests.delete(
f "http://localhost:8001/api/v1/api-keys/ { key_info[ 'api_key' ] } " ,
headers = { "Authorization" : f "Bearer { admin_key } " }
)
print ( f "Revoked key: { key_info[ 'api_key' ][: 20 ] } ..." )
print ( f "All keys revoked for { user_email } " )
# Emergency revocation
emergency_revoke_user_keys( "[email protected] " )
Audit and Monitoring
Key Usage Tracking
Monitor API key usage for security auditing:
def audit_api_key_usage ():
"""Generate usage report for all API keys"""
response = requests.get(
"http://localhost:8001/api/v1/api-keys" ,
headers = { "Authorization" : f "Bearer { admin_key } " }
)
keys = response.json()[ "data" ]
report = []
for key in keys:
# Get detailed info
detail_response = requests.get(
f "http://localhost:8001/api/v1/api-keys/ { key[ 'api_key' ] } " ,
headers = { "Authorization" : f "Bearer { admin_key } " }
)
details = detail_response.json()[ "data" ]
report.append({
"user" : details[ "user_email" ],
"project" : details[ "project_name" ],
"created" : details[ "created_at" ],
"last_used" : details.get( "last_used" , "Never" ),
"status" : details[ "status" ]
})
return report
# Generate audit report
report = audit_api_key_usage()
for entry in report:
print ( f " { entry[ 'user' ] } - { entry[ 'project' ] } - { entry[ 'status' ] } " )
Inactive Key Detection
from datetime import datetime, timedelta
def find_inactive_keys ( inactive_days = 30 ):
"""Find keys not used in specified days"""
response = requests.get(
"http://localhost:8001/api/v1/api-keys" ,
headers = { "Authorization" : f "Bearer { admin_key } " }
)
keys = response.json()[ "data" ]
inactive = []
for key_info in keys:
# Get detailed info with last_used
detail_response = requests.get(
f "http://localhost:8001/api/v1/api-keys/ { key_info[ 'api_key' ] } " ,
headers = { "Authorization" : f "Bearer { admin_key } " }
)
details = detail_response.json()[ "data" ]
last_used = details.get( "last_used" )
if last_used:
last_used_date = datetime.fromisoformat(
last_used.replace( 'Z' , '+00:00' )
)
days_inactive = (datetime.now() - last_used_date).days
if days_inactive > inactive_days:
inactive.append({
"key" : key_info[ "api_key" ],
"user" : details[ "user_email" ],
"days_inactive" : days_inactive
})
return inactive
# Find keys inactive for 30+ days
inactive = find_inactive_keys( inactive_days = 30 )
for key in inactive:
print ( f " { key[ 'user' ] } : { key[ 'days_inactive' ] } days inactive" )
Security Best Practices
Rotate API keys every 90 days or less. Implement automated rotation to ensure compliance. # Rotate a specific key
curl -X POST "http://localhost:8001/api/v1/api-keys/rotate" \
-H "Authorization: Bearer ${ ADMIN_KEY }" \
-H "Content-Type: application/json" \
-d '{"api_key": "gw_key_to_rotate"}'
Principle of Least Privilege
Generate separate API keys for each project-user combination. Never share keys across projects. # Generate project-specific keys
dev_key = generate_api_key(user, "development-project" )
prod_key = generate_api_key(user, "production-project" )
Track API key usage patterns and alert on unusual activity:
Sudden increase in requests
Requests from unexpected IP addresses
Failed authentication attempts
Key usage outside business hours
Never store API keys in:
Version control (git)
Plain text files
Client-side code
Unsecured databases
Use:
Environment variables
Secret management systems (AWS Secrets Manager, HashiCorp Vault)
Encrypted configuration files
Next Steps
User Endpoints Manage users who own API keys
Project Endpoints Manage project access
Authentication Learn about admin API key authentication
System Operations Backup and restore operations