Multiple API Keys
Support for multiple API keys for different clients or environments
Mend uses API key authentication to secure all API endpoints under /api/v1/*. This provides a simple yet effective way to control access to your media processing API.
Multiple API Keys
Support for multiple API keys for different clients or environments
Flexible Headers
Accept API keys via X-API-Key header or Authorization: Bearer token
Backward Compatible
Can be disabled by leaving the api_keys array empty
Secure by Default
All job endpoints are protected, public endpoints remain accessible
Set API Keys in config.yaml
server: port: 8080 mode: release read_timeout: 30s write_timeout: 30s api_keys: - "${API_KEY_1}" - "${API_KEY_2}" # Optional: add more keysSet Environment Variables
Create or update your .env file:
# Generate a secure keyAPI_KEY_1=$(openssl rand -hex 32)echo "API_KEY_1=$API_KEY_1" >> .env
# Or manually setAPI_KEY_1=your_secure_random_key_hereAPI_KEY_2=another_key_for_different_clientGenerate Secure Keys
# 64 character hex stringopenssl rand -hex 32uuidgenopenssl rand -base64 32Example output:
a7f3e8c9d2b1f4e6a8c5d9e2f7b3a6c8d1e4f9b2c5a8e3d6f1b4c7e9a2d5f8b1curl -X POST http://localhost:8080/api/v1/jobs/image/resize \ -H "Content-Type: application/json" \ -H "X-API-Key: your_api_key_here" \ -d '{ "source_bucket": "my-bucket", "source_key": "image.jpg", "dest_bucket": "my-bucket", "dest_key": "image-resized.jpg", "width": 800, "height": 600 }'curl -X POST http://localhost:8080/api/v1/jobs/image/resize \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your_api_key_here" \ -d '{ ... }'# Set in your shellexport API_KEY_1="your_api_key_here"
# Use in scriptscurl -H "X-API-Key: $API_KEY_1" \ http://localhost:8080/api/v1/jobs/image/resize \ ...All endpoints under /api/v1/*:
POST /api/v1/jobs/image/resizePOST /api/v1/jobs/image/optimizePOST /api/v1/jobs/image/watermarkPOST /api/v1/jobs/image/colorsPOST /api/v1/jobs/image/ai/keywordsPOST /api/v1/jobs/video/thumbnailPOST /api/v1/jobs/audio/convertPOST /api/v1/jobs/analyzeGET /api/v1/jobs/:idGET /health - Health checkGET /metrics - Prometheus metricsGET /swagger/* - API documentation# Generate new keyNEW_KEY=$(openssl rand -hex 32)
# Add to config (keep old key temporarily)server: api_keys: - "${API_KEY_1}" # Old key - "${API_KEY_NEW}" # New key
# Update clients to use new key# Remove old key after migration# Developmentserver: api_keys: - "${DEV_API_KEY}"
# Productionserver: api_keys: - "${PROD_API_KEY_1}" - "${PROD_API_KEY_2}"Check logs for authentication failures:
# View auth-related logsdocker-compose logs api | grep "API key"
# Look for patternsdocker-compose logs api | grep "invalid API key"server: api_keys: - "${MOBILE_APP_KEY}" - "${WEB_APP_KEY}" - "${ADMIN_KEY}"server: api_keys: - "${FRONTEND_SERVICE_KEY}" - "${BATCH_PROCESSOR_KEY}" - "${MONITORING_KEY}"server: api_keys: - "${API_KEY_1}" # Production - "${DEV_KEY}" # Development/testingcurl -i -H "X-API-Key: your_valid_key" \ http://localhost:8080/api/v1/jobs/image/resize \ -H "Content-Type: application/json" \ -d '{ ... }'
# Expected: 202 Accepted (or 400 if invalid payload)curl -i -H "X-API-Key: invalid_key" \ http://localhost:8080/api/v1/jobs/image/resize
# Expected: 401 Unauthorizedcurl -i http://localhost:8080/api/v1/jobs/image/resize
# Expected: 401 Unauthorizedcurl -i http://localhost:8080/health
# Expected: 200 OK (no auth required)server: api_keys: [] # Empty array disables authThe middleware will log a warning:
API key authentication is disabled - no keys configuredThe authentication is implemented in /internal/api/middleware/auth.go:
X-API-Key first, then Authorization: BearerSolution:
X-API-Key headerSolution:
config.yamlSolution:
config.yamlapi_keys array is not emptySolution:
/health, /metrics, /swagger/*) should always workIf you’re upgrading from a version without authentication:
Update config structure
server: api_keys: - "${API_KEY_1}"Generate and set API key
echo "API_KEY_1=$(openssl rand -hex 32)" >> .envUpdate all API clients
X-API-Key header to all requestsTest thoroughly
Optional: Disable temporarily
server: api_keys: [] # Disable during migration