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:
| Phase | Old Key | New Key | Duration |
|---|---|---|---|
| Before rotation | Valid | N/A | β |
| Grace period | Valid | Valid | 1-168 hours (default: 24h) |
| After grace period | Invalid | Valid | Permanent |
Step-by-Step Rotationβ
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
}
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β
| Scenario | Recommended Grace Period |
|---|---|
| Single application, quick deploy | 1-4 hours |
| Multiple services, rolling deploy | 12-24 hours |
| Partner integrations, external consumers | 48-72 hours |
| Compliance rotation (scheduled) | 24 hours |
| Emergency rotation (key compromised) | 1 hour |
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:
| Setting | Value |
|---|---|
| Cache TTL | 5 minutes |
| Max entries | 10,000 |
| Invalidation | Automatic on rotation |
When you rotate a key:
- The Control Plane notifies the gateway
- The gateway invalidates the cache entry for the old key
- The next request re-validates against the Control Plane
- 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β
- Navigate to Subscriptions in the Console
- Find the subscription to rotate
- Click the Rotate Key button
- Set the grace period (default: 24 hours)
- 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β
| Problem | Cause | Fix |
|---|---|---|
| Old key rejected during grace period | Grace period expired | Check old_key_expires_at timestamp |
| New key returns 401 | Subscription not active | Verify subscription status is active |
| Both keys rejected | Subscription suspended/revoked | Check subscription status |
| Key rotation returns 404 | Wrong subscription ID | Verify the subscription exists |
Relatedβ
- Subscription Lifecycle β Subscription states and transitions
- Quota Enforcement β Rate limits and quotas
- Gateway Admin API β Cache management endpoints
- Security Configuration β Security best practices