Skip to content

Authentication Guide

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

  1. Set API Keys in config.yaml

    config.yaml
    server:
    port: 8080
    mode: release
    read_timeout: 30s
    write_timeout: 30s
    api_keys:
    - "${API_KEY_1}"
    - "${API_KEY_2}" # Optional: add more keys
  2. Set Environment Variables

    Create or update your .env file:

    .env
    # Generate a secure key
    API_KEY_1=$(openssl rand -hex 32)
    echo "API_KEY_1=$API_KEY_1" >> .env
    # Or manually set
    API_KEY_1=your_secure_random_key_here
    API_KEY_2=another_key_for_different_client
  3. Generate Secure Keys

    Terminal window
    # 64 character hex string
    openssl rand -hex 32

    Example output:

    a7f3e8c9d2b1f4e6a8c5d9e2f7b3a6c8d1e4f9b2c5a8e3d6f1b4c7e9a2d5f8b1

Option 1: X-API-Key Header Recommended

Section titled “Option 1: X-API-Key Header ”
Terminal window
curl -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
}'
Terminal window
curl -X POST http://localhost:8080/api/v1/jobs/image/resize \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_api_key_here" \
-d '{ ... }'
Terminal window
# Set in your shell
export API_KEY_1="your_api_key_here"
# Use in scripts
curl -H "X-API-Key: $API_KEY_1" \
http://localhost:8080/api/v1/jobs/image/resize \
...

Protected Endpoints Require API Key

Section titled “Protected Endpoints ”

All endpoints under /api/v1/*:

  • POST /api/v1/jobs/image/resize
  • POST /api/v1/jobs/image/optimize
  • POST /api/v1/jobs/image/watermark
  • POST /api/v1/jobs/image/colors
  • POST /api/v1/jobs/image/ai/keywords
  • POST /api/v1/jobs/video/thumbnail
  • POST /api/v1/jobs/audio/convert
  • POST /api/v1/jobs/analyze
  • GET /api/v1/jobs/:id

Public Endpoints No Authentication

Section titled “Public Endpoints ”
  • GET /health - Health check
  • GET /metrics - Prometheus metrics
  • GET /swagger/* - API documentation
  • Use cryptographically secure random generation
  • Minimum 32 characters
  • Use hex or base64 encoding
Terminal window
# Generate new key
NEW_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
config.yaml
# Development
server:
api_keys:
- "${DEV_API_KEY}"
# Production
server:
api_keys:
- "${PROD_API_KEY_1}"
- "${PROD_API_KEY_2}"

Check logs for authentication failures:

Terminal window
# View auth-related logs
docker-compose logs api | grep "API key"
# Look for patterns
docker-compose logs api | grep "invalid API key"
server:
api_keys:
- "${MOBILE_APP_KEY}"
- "${WEB_APP_KEY}"
- "${ADMIN_KEY}"
Terminal window
curl -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)
Terminal window
curl -i -H "X-API-Key: invalid_key" \
http://localhost:8080/api/v1/jobs/image/resize
# Expected: 401 Unauthorized
Terminal window
curl -i http://localhost:8080/api/v1/jobs/image/resize
# Expected: 401 Unauthorized
Terminal window
curl -i http://localhost:8080/health
# Expected: 200 OK (no auth required)
config.yaml
server:
api_keys: [] # Empty array disables auth

The middleware will log a warning:

API key authentication is disabled - no keys configured

The authentication is implemented in /internal/api/middleware/auth.go:

  • Lookup Method: O(1) hash map lookup for performance
  • Header Priority: Checks X-API-Key first, then Authorization: Bearer
  • Logging: Logs all authentication failures with IP and path
  • Backward Compatible: Gracefully handles empty key configuration

Solution:

  • Ensure you’re including the X-API-Key header
  • Check header spelling (case-sensitive)
  • Verify the header value is not empty

Solution:

  • Verify the key matches one in config.yaml
  • Check for extra spaces or newlines in the key
  • Ensure environment variables are loaded correctly
  • Restart the API server after config changes

Solution:

  • Add at least one API key to config.yaml
  • Ensure environment variables are set
  • Check that api_keys array is not empty

Solution:

  • Public endpoints (/health, /metrics, /swagger/*) should always work
  • Check if you’re using the correct path
  • Verify the server is running

If you’re upgrading from a version without authentication:

  1. Update config structure

    config.yaml
    server:
    api_keys:
    - "${API_KEY_1}"
  2. Generate and set API key

    Terminal window
    echo "API_KEY_1=$(openssl rand -hex 32)" >> .env
  3. Update all API clients

    • Add X-API-Key header to all requests
    • Update example scripts and documentation
  4. Test thoroughly

    • Verify all endpoints work with new auth
    • Check that public endpoints still work
    • Monitor logs for auth failures
  5. Optional: Disable temporarily

    server:
    api_keys: [] # Disable during migration