Skip to main content

API Key Rotation

Rotate API keys with zero downtime using STOA's grace period mechanism β€” both old and new keys work during the transition window.

How It Works​

When you rotate a key, STOA doesn't immediately invalidate the old one. Instead, it creates a grace period where both keys are valid:

PhaseOld KeyNew KeyDuration
Before rotationValidN/Aβ€”
Grace periodValidValid1-168 hours (default: 24h)
After grace periodInvalidValidPermanent

Step-by-Step Rotation​

Configure your environment

The examples below use environment variables. Set them for your STOA instance:

export STOA_API_URL="https://api.gostoa.dev"       # Replace with your domain
export STOA_AUTH_URL="https://auth.gostoa.dev" # Keycloak OIDC provider
export STOA_GATEWAY_URL="https://mcp.gostoa.dev" # MCP Gateway endpoint

Self-hosted? Replace gostoa.dev with your domain.

1. Rotate the Key​

curl -X POST "${STOA_API_URL}/v1/subscriptions/${SUB_ID}/rotate-key" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"grace_period_hours": 24
}'

Response:

{
"subscription_id": "sub-uuid-123",
"new_api_key": "stoa_sk_e7f8g9h0i1j2k3l4m5n6o7p8q9r0s1t2",
"new_api_key_prefix": "stoa_sk_e7f8",
"old_key_expires_at": "2026-02-14T10:00:00Z",
"grace_period_hours": 24,
"rotation_count": 3
}
Save the New Key

The new_api_key is shown only once. Store it securely before proceeding.

2. Update Your Applications​

Deploy the new key to your applications. During the grace period, both keys work:

# Old key β€” still works during grace period
curl "${STOA_GATEWAY_URL}/apis/acme/billing/v1/invoices" \
-H "X-API-Key: stoa_sk_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"

# New key β€” works immediately
curl "${STOA_GATEWAY_URL}/apis/acme/billing/v1/invoices" \
-H "X-API-Key: stoa_sk_e7f8g9h0i1j2k3l4m5n6o7p8q9r0s1t2"

3. Verify the Rotation​

Check the rotation status:

curl "${STOA_API_URL}/v1/subscriptions/${SUB_ID}/rotation-info" \
-H "Authorization: Bearer ${TOKEN}"

Response:

{
"subscription_id": "sub-uuid-123",
"api_key_prefix": "stoa_sk_e7f8",
"has_previous_key": true,
"previous_key_expires_at": "2026-02-14T10:00:00Z",
"rotation_count": 3,
"last_rotated_at": "2026-02-13T10:00:00Z"
}

4. Wait for Grace Period to Expire​

After the grace period expires, the old key is automatically invalidated. No action needed.

Grace Period Guidelines​

ScenarioRecommended Grace Period
Single application, quick deploy1-4 hours
Multiple services, rolling deploy12-24 hours
Partner integrations, external consumers48-72 hours
Compliance rotation (scheduled)24 hours
Emergency rotation (key compromised)1 hour
Emergency Rotation

If a key is compromised, use a 1-hour grace period. This gives your team just enough time to deploy the new key while minimizing the exposure window.

Gateway Caching​

The gateway caches API key validation results to reduce latency:

SettingValue
Cache TTL5 minutes
Max entries10,000
InvalidationAutomatic on rotation

When you rotate a key:

  1. The Control Plane notifies the gateway
  2. The gateway invalidates the cache entry for the old key
  3. The next request re-validates against the Control Plane
  4. The new validation result is cached

Worst case: A rotated key may still be cached for up to 5 minutes after the grace period expires. For immediate invalidation, the admin can clear the gateway cache:

curl -X POST "${STOA_GATEWAY_URL}/admin/cache/clear" \
-H "Authorization: Bearer ${ADMIN_TOKEN}"

Rotation via Console​

  1. Navigate to Subscriptions in the Console
  2. Find the subscription to rotate
  3. Click the Rotate Key button
  4. Set the grace period (default: 24 hours)
  5. Copy the new key from the confirmation dialog

Monitoring Rotations​

Track rotation health via the subscription's rotation_count and last_rotated_at fields:

# List all subscriptions with rotation info
curl "${STOA_API_URL}/v1/subscriptions/tenant/${TENANT_ID}" \
-H "Authorization: Bearer ${TOKEN}" | \
jq '.subscriptions[] | {api_key_prefix, rotation_count, last_rotated_at}'

Rotation Best Practices​

  • Rotate regularly β€” Every 90 days for production keys
  • Automate rotation β€” Use CI/CD pipelines or scheduled scripts
  • Monitor rotation count β€” Unusual spikes may indicate issues
  • Test with grace period β€” Always use a grace period in production
  • Audit trail β€” Every rotation is logged with timestamp and user

Troubleshooting​

ProblemCauseFix
Old key rejected during grace periodGrace period expiredCheck old_key_expires_at timestamp
New key returns 401Subscription not activeVerify subscription status is active
Both keys rejectedSubscription suspended/revokedCheck subscription status
Key rotation returns 404Wrong subscription IDVerify the subscription exists