Revoke an active developer key to immediately prevent its use for API authentication. This action is permanent and cannot be undone - revoked keys cannot be reactivated.
You cannot revoke the developer key you’re currently using for authentication. Use a different active key to revoke others. Always ensure you have at least one active key before revoking.
Authentication
Requires valid JWT token with developer role and an active developer key (different from the one being revoked).
Bearer JWT access token obtained from login
Active developer key for authentication (must be different from the key being revoked)
Path Parameters
Response
Returns 204 No Content on successful revocation. No response body is returned.
Example Request
curl -X DELETE https://api.vibecoding.ad/api/v1/auth/developer-keys/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "X-User-Role: developer" \
-H "X-Developer-Key: ak_different_active_key_here_123"
Example Response
No response body is returned for successful revocations.
Use Cases
Revoke Compromised Keys
Immediately deactivate keys that may have been exposed:
async function revokeCompromisedKey(
keyId: string,
jwtToken: string,
safeKey: string
): Promise<void> {
const response = await fetch(
`https://api.vibecoding.ad/api/v1/auth/developer-keys/${keyId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'X-User-Role': 'developer',
'X-Developer-Key': safeKey
}
}
);
if (!response.ok) {
throw new Error(`Failed to revoke key: ${response.status}`);
}
console.log(`Key ${keyId} has been revoked`);
// Alert security team
await notifySecurityTeam({
action: 'key_revoked',
keyId,
reason: 'compromised',
timestamp: new Date().toISOString()
});
}
Clean Up Unused Keys
Remove keys that haven’t been used recently:
interface DeveloperKey {
id: string;
name: string;
last_used_at: string | null;
created_at: string;
}
async function cleanupUnusedKeys(
keys: DeveloperKey[],
jwtToken: string,
activeKey: string,
maxIdleDays: number = 90
): Promise<void> {
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - maxIdleDays);
const unusedKeys = keys.filter(key => {
// Skip the key we're using for authentication
if (key.id === getActiveKeyId(activeKey)) return false;
// Never used or not used in maxIdleDays
if (!key.last_used_at) return true;
return new Date(key.last_used_at) < cutoffDate;
});
for (const key of unusedKeys) {
console.log(`Revoking unused key: ${key.name} (${key.id})`);
await fetch(
`https://api.vibecoding.ad/api/v1/auth/developer-keys/${key.id}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'X-User-Role': 'developer',
'X-Developer-Key': activeKey
}
}
);
console.log(`✓ Revoked: ${key.name}`);
}
console.log(`Cleaned up ${unusedKeys.length} unused keys`);
}
Offboard Team Members
Revoke keys when team members leave:
async function offboardTeamMember(
memberName: string,
jwtToken: string,
adminKey: string
): Promise<void> {
// Step 1: List all keys
const listResponse = await fetch(
'https://api.vibecoding.ad/api/v1/auth/developer-keys',
{
headers: {
'Authorization': `Bearer ${jwtToken}`,
'X-User-Role': 'developer',
'X-Developer-Key': adminKey
}
}
);
const keys = await listResponse.json();
// Step 2: Find keys belonging to team member
const memberKeys = keys.filter((key: DeveloperKey) =>
key.name.includes(memberName)
);
if (memberKeys.length === 0) {
console.log(`No keys found for ${memberName}`);
return;
}
// Step 3: Revoke all member keys
for (const key of memberKeys) {
await fetch(
`https://api.vibecoding.ad/api/v1/auth/developer-keys/${key.id}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'X-User-Role': 'developer',
'X-Developer-Key': adminKey
}
}
);
console.log(`Revoked key: ${key.name} (${key.key_prefix})`);
}
console.log(`Offboarded ${memberName}: ${memberKeys.length} keys revoked`);
}
Key Rotation with Graceful Cutover
Revoke old keys after new ones are deployed:
async function completeKeyRotation(
oldKeyId: string,
newKeyPrefix: string,
jwtToken: string,
newKey: string,
gracePeriodMinutes: number = 30
): Promise<void> {
console.log(`Starting ${gracePeriodMinutes}-minute grace period...`);
console.log('Deploy new key to all services during this time.');
// Wait for grace period to allow services to pick up new key
await new Promise(resolve =>
setTimeout(resolve, gracePeriodMinutes * 60 * 1000)
);
// Verify new key is working
const testResponse = await fetch(
'https://api.vibecoding.ad/api/v1/auth/developer-keys',
{
headers: {
'Authorization': `Bearer ${jwtToken}`,
'X-User-Role': 'developer',
'X-Developer-Key': newKey
}
}
);
if (!testResponse.ok) {
throw new Error('New key verification failed! Aborting revocation.');
}
// Revoke old key using new key
const revokeResponse = await fetch(
`https://api.vibecoding.ad/api/v1/auth/developer-keys/${oldKeyId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'X-User-Role': 'developer',
'X-Developer-Key': newKey
}
}
);
if (revokeResponse.ok) {
console.log(`✓ Old key revoked successfully`);
console.log(`✓ Rotation complete: now using ${newKeyPrefix}`);
}
}
Security Considerations
Revocation takes effect immediately. Any in-flight API requests using the revoked key will fail with a 403 Forbidden error.
When to Revoke Keys
-
Compromised Keys: Immediately revoke if a key is exposed in code repositories, logs, or insecure channels
-
Employee Offboarding: Revoke all keys assigned to departing team members on their last day
-
Rotation Schedule: Revoke old keys after rotating to new ones (90-day rotation recommended)
-
Unused Keys: Revoke keys that haven’t been used in 90+ days
-
Environment Decommission: Revoke keys when shutting down environments (e.g., old staging environments)
-
Security Incidents: Revoke all keys during security incident response
Best Practices
-
Maintain Backup Key: Always keep at least 2 active keys to avoid locking yourself out
-
Document Revocations: Log all key revocations with reasons and timestamps
-
Verify Before Revoking: Ensure services using the key have been migrated to new keys
-
Immediate Action: Don’t delay revocation of compromised keys
-
Communicate Changes: Notify team members before revoking shared environment keys
Error Responses
Key Already Revoked (400)
{
"detail": "Developer key is already revoked or inactive"
}
The key has already been revoked or was never active.
Unauthorized (401)
{
"detail": "Could not validate credentials"
}
Invalid or missing JWT token.
Forbidden (403)
{
"detail": "Key does not belong to the authenticated developer"
}
Attempting to revoke a key that belongs to a different developer account, or using an invalid/revoked developer key for authentication.
Cannot Revoke Active Key (403)
{
"detail": "Cannot revoke the developer key currently being used for authentication"
}
Attempting to revoke the same key being used in the X-Developer-Key header.
Key Not Found (404)
{
"detail": "Developer key not found"
}
The specified key_id does not exist or was deleted.
{
"detail": [
{
"loc": ["path", "key_id"],
"msg": "value is not a valid uuid",
"type": "type_error.uuid"
}
]
}
The key_id parameter is not a valid UUID format.
Revocation Effects
After revocation, the key:
- ✅ Immediately stops authenticating API requests
- ✅ Disappears from the List Developer Keys endpoint
- ✅ Returns 403 Forbidden when used in API requests
- ✅ Cannot be reactivated or restored
- ✅ Frees up one slot toward the 10-key limit
(((REPLACE_THIS_WITH_IMAGE: developer-key-revoked-confirmation.png: Success message after revoking developer key with key prefix shown and warning that it cannot be undone)))
Related Pages
The access token received from the authorization server in the OAuth 2.0 flow.