Admin Token Rotation API¶
Overview¶
Admin-only endpoints for emergency token rotation during security incidents.
Base URL: ${BASE_URL}/api/v1/admin
Authentication: Admin role required (AuthLevel.ADMIN with Casbin RBAC)
Setup¶
Set your environment base URL before running commands:
# Development
export BASE_URL="https://dashtam.local"
# Test
export BASE_URL="https://test.dashtam.local"
# Production
export BASE_URL="https://api.dashtam.com"
Endpoints Summary¶
| Resource | Method | Endpoint | Description |
|---|---|---|---|
| Security Rotations | POST | /security/rotations |
Trigger global token rotation |
| User Rotations | POST | /users/{user_id}/rotations |
Trigger per-user token rotation |
| Security Config | GET | /security/config |
Get current security configuration |
Global Token Rotation¶
POST /admin/security/rotations¶
Trigger global token rotation. Invalidates ALL refresh tokens with version below new minimum.
Use Cases:
- Database breach detected
- Security vulnerability patched
- Compliance requirement
Request:
curl -k -X POST "${BASE_URL}/api/v1/admin/security/rotations" \
-H "Content-Type: application/json" \
-d '{
"reason": "Database breach detected - rotating all tokens"
}'
Success Response (201 Created):
{
"previous_version": 1,
"new_version": 2,
"grace_period_seconds": 300,
"message": "Global token rotation triggered successfully"
}
Error Responses:
401 Unauthorized- Not authenticated403 Forbidden- Not authorized (admin only)422 Unprocessable Entity- Missing reason field500 Internal Server Error- Rotation failed
Notes:
- All existing refresh tokens with
token_version < new_versionwill fail validation - Grace period (default 300s) allows gradual transition
- Action is logged via domain events for audit trail
Per-User Token Rotation¶
POST /admin/users/{user_id}/rotations¶
Trigger token rotation for a specific user. Invalidates only that user's tokens.
Use Cases:
- Suspicious account activity
- User account compromise
- Administrative action
Request:
export USER_ID="550e8400-e29b-41d4-a716-446655440000"
curl -k -X POST "${BASE_URL}/api/v1/admin/users/${USER_ID}/rotations" \
-H "Content-Type: application/json" \
-d '{
"reason": "Suspicious activity detected on account"
}'
Success Response (201 Created):
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"previous_version": 1,
"new_version": 2,
"message": "User token rotation triggered successfully"
}
Error Responses:
401 Unauthorized- Not authenticated403 Forbidden- Not authorized (admin only)404 Not Found- User not found422 Unprocessable Entity- Missing reason field500 Internal Server Error- Rotation failed
Notes:
- Only affects the specified user's tokens
- Other users' tokens remain valid
- User must re-authenticate after rotation
Security Configuration¶
GET /admin/security/config¶
Retrieve current security configuration including token version and grace period.
Request:
Success Response (200 OK):
{
"global_min_token_version": 2,
"grace_period_seconds": 300,
"last_rotation_at": "2025-11-27T03:00:00Z",
"last_rotation_reason": "Database breach detected"
}
Error Responses:
401 Unauthorized- Not authenticated403 Forbidden- Not authorized (admin only)
Notes:
last_rotation_atandlast_rotation_reasonare null if never rotated- Use to verify rotation was applied correctly
Testing Flow¶
Complete Rotation Test¶
# Ensure BASE_URL is set (see Setup section above)
# Step 1: Check current config
curl -k -X GET "${BASE_URL}/api/v1/admin/security/config"
# Note the global_min_token_version
# Step 2: Trigger global rotation
curl -k -X POST "${BASE_URL}/api/v1/admin/security/rotations" \
-H "Content-Type: application/json" \
-d '{"reason": "Testing rotation mechanism"}'
# Response shows previous_version and new_version
# Step 3: Verify config updated
curl -k -X GET "${BASE_URL}/api/v1/admin/security/config"
# global_min_token_version should be incremented
# last_rotation_reason should match
# Step 4: Test per-user rotation
export USER_ID="<insert-user-uuid>"
curl -k -X POST "${BASE_URL}/api/v1/admin/users/${USER_ID}/rotations" \
-H "Content-Type: application/json" \
-d '{"reason": "Testing per-user rotation"}'
Verify Token Rejection¶
# After rotation, old refresh tokens should fail:
# 1. Login and get tokens (before rotation)
# 2. Trigger rotation
# 3. Wait for grace period to expire (default 300s)
# 4. Try to refresh with old token
curl -k -X POST "${BASE_URL}/api/v1/tokens" \
-H "Content-Type: application/json" \
-d '{"refresh_token": "<old-refresh-token>"}'
# Should return 401 Unauthorized
Troubleshooting¶
Issue: Rotation returns 500 Internal Server Error
- Check database connectivity
- Verify security_config table exists
- Check application logs for specific error
Issue: User not found (404)
- Verify user_id is a valid UUID
- Confirm user exists in database
Issue: Tokens not being rejected after rotation
- Verify grace period has expired (default 300s)
- Check token_version in refresh_tokens table
- Verify global_min_token_version was incremented
Rate Limiting¶
Admin endpoints use standard rate limiting:
| Policy | Max Requests | Refill Rate | Scope | Endpoints |
|---|---|---|---|---|
| API_READ | 100 | 100/min | User | GET /admin/security/config |
| API_WRITE | 50 | 50/min | User | POST /admin/security/rotations, POST /admin/users/{id}/rotations |
Implementation References¶
- Route Registry: All admin endpoints are defined in
src/presentation/routers/api/v1/routes/registry.pywithAuthLevel.ADMINrequiring admin role. - Handler Module:
src/presentation/routers/api/v1/admin/token_rotation.py - Domain Events: Token rotation emits domain events for audit logging.
Created: 2025-11-27 | Last Updated: 2026-01-10