Files

Asymmetric Tokenizer

EdDSA (Ed25519) tokenizer with support for zero-downtime key rotation.

Features

  • Single-key mode - Simple setup with one active key
  • Two-key mode - Active + retiring keys for zero-downtime rotation
  • JWKS endpoint - Publishes all valid public keys for token verification

Configuration

The tokenizer uses environment variables to specify key file paths:

Environment Variable Required Description
MG_AUTH_KEYS_ACTIVE_KEY_PATH Yes Path to active private key file
MG_AUTH_KEYS_RETIRING_KEY_PATH No Path to retiring private key file (for rotation)

Please note that key names are used as key IDs (kid).

Single-Key Mode

Set only the active key path:

export MG_AUTH_KEYS_ACTIVE_KEY_PATH="./keys/private.key"

The tokenizer will:

  • Issue new tokens signed with the active key
  • Verify tokens using the active key
  • Return one public key in JWKS endpoint

Two-Key Mode (Key Rotation)

Set both active and retiring key paths:

export MG_AUTH_KEYS_ACTIVE_KEY_PATH="./keys/active.key"
export MG_AUTH_KEYS_RETIRING_KEY_PATH="./keys/retiring.key"

The tokenizer will:

  • Issue new tokens signed with the active key
  • Verify tokens using both active and retiring keys
  • Return both public keys in JWKS endpoint

Key Rotation Process

Zero-downtime key rotation in 3 simple steps:

1. Generate New Key

openssl genpkey -algorithm Ed25519 -out keys/new.key

2. Update Environment & Restart

Move the current active key to retiring position and set the new key as active:

# Before rotation
MG_AUTH_KEYS_ACTIVE_KEY_PATH="./keys/current.key"
MG_AUTH_KEYS_RETIRING_KEY_PATH=""  # No retiring key

# During rotation (both keys active for grace period)
MG_AUTH_KEYS_ACTIVE_KEY_PATH="./keys/new.key"
MG_AUTH_KEYS_RETIRING_KEY_PATH="./keys/current.key"

# After rotation (restart service with new config)
docker-compose restart auth

During the grace period, tokens signed with either key remain valid.

3. Clean Up After Grace Period

After the grace period expires (typically 7-30 days), remove the retiring key:

# Remove retiring key configuration
MG_AUTH_KEYS_ACTIVE_KEY_PATH="./keys/new.key"
MG_AUTH_KEYS_RETIRING_KEY_PATH=""  # Remove retiring key

# Restart service
docker-compose restart auth

# Delete old key file
rm keys/current.key

Grace Period Recommendations

Recommended: 168 hours (7 days) Minimum: 24 hours Maximum: 720 hours (30 days)

The grace period should be longer than your longest-lived access token duration.

Security Best Practices

  • Store private keys with 0600 permissions

  • Use cryptographically secure key generation:

    openssl genpkey -algorithm Ed25519 -out private.key
    chmod 600 private.key
    
  • Rotate keys regularly:

    • Standard environments: every 90 days
    • High-security environments: every 30 days
  • Never commit keys to version control

  • Use secrets management in production (HashiCorp Vault, AWS Secrets Manager, etc.)

Example: Complete Rotation

# Day 0: Normal operation
export MG_AUTH_KEYS_ACTIVE_KEY_PATH="./keys/key-2024.pem"
export MG_AUTH_KEYS_RETIRING_KEY_PATH=""

# Day 1: Start rotation - generate new key
openssl genpkey -algorithm Ed25519 -out ./keys/key-2025.pem
chmod 600 ./keys/key-2025.pem

# Day 1: Update config and restart
export MG_AUTH_KEYS_ACTIVE_KEY_PATH="./keys/key-2025.pem"
export MG_AUTH_KEYS_RETIRING_KEY_PATH="./keys/key-2024.pem"
docker-compose restart auth

# Day 8: Grace period expired - remove old key
export MG_AUTH_KEYS_RETIRING_KEY_PATH=""
docker-compose restart auth
rm ./keys/key-2024.pem

Troubleshooting

Active key not found

Error: active key file not found: ./keys/active.key

Solution: Ensure the file exists and path is correct. Verify MG_AUTH_KEYS_ACTIVE_KEY_PATH environment variable.

Retiring key warning

If the retiring key path is set but the file is missing or invalid, the tokenizer logs a warning but continues with only the active key:

WARN: failed to load retiring key, continuing without it

This is by design - a missing retiring key won't prevent startup.

Invalid key format

Error: failed to parse private key

Solution: Ensure you're using Ed25519 keys in PEM format (PKCS8).