Key lifecycle
After issuing an API key, you can update its metadata, rotate the secret, or revoke it. All lifecycle operations use the admin plane.
First, issue a key to work with:
- CLI
- curl
RESPONSE=$(talos keys issue "lifecycle-test" \
--actor user_1 \
--scopes "read,write" \
--metadata '{"team":"backend"}' \
--format json \
-e "$TALOS_URL" 2>/dev/null)
echo "$RESPONSE" | jq .
export API_SECRET=$(echo "$RESPONSE" | jq -er '.secret')
export KEY_ID=$(echo "$RESPONSE" | jq -er '.issued_api_key.key_id')
ISSUE_RESP=$(curl -s -X POST "$TALOS_URL/v2alpha1/admin/issuedApiKeys" \
-H "Content-Type: application/json" \
-d '{"name":"lifecycle-test","actor_id":"user_1","scopes":["read","write"],"metadata":{"team":"backend"}}')
echo "$ISSUE_RESP" | jq .
export API_SECRET=$(echo "$ISSUE_RESP" | jq -er '.secret')
export KEY_ID=$(echo "$ISSUE_RESP" | jq -er '.key_id')
When you set ttl on issue or import requests, the HTTP API accepts extended formats such as 1y, 1mo, 1w, 1d, and
compounds like 1y6mo in addition to standard Go durations. The current CLI --ttl flags still expect standard Go duration
strings; see the configuration reference for the canonical duration format summary.
Update key metadata
Use PATCH to update a key's name, scopes, metadata, or rate limit policy without changing the secret:
- CLI
- curl
talos keys issued update "$KEY_ID" \
--name "lifecycle-test-updated" \
--scopes "read" \
--metadata '{"team": "backend", "tier": "premium"}' \
-e "$TALOS_URL"
curl -s -X PATCH "$TALOS_URL/v2alpha1/admin/issuedApiKeys/$KEY_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "lifecycle-test-updated",
"scopes": ["read"],
"metadata": {"team": "backend", "tier": "premium"},
"update_mask": {"paths": ["name", "scopes", "metadata"]}
}' | jq .
Update mask
The update_mask field controls which fields are modified. Only fields listed in paths are changed. This follows the
AIP-134 standard for partial updates.
Updatable fields include name, scopes, metadata, and rate_limit_policy. For the complete field reference, see the
UpdateIssuedAPIKey API reference.
Rotate a key
Rotation creates a new key with a new secret and immediately revokes the old one:
- CLI
- curl
RESPONSE=$(talos keys issued rotate "$KEY_ID" \
--scopes "read,write,admin" \
--format json \
-e "$TALOS_URL" 2>/dev/null)
echo "$RESPONSE" | jq .
export API_SECRET=$(echo "$RESPONSE" | jq -er '.secret')
export KEY_ID=$(echo "$RESPONSE" | jq -er '.issued_api_key.key_id')
RESPONSE=$(curl -s -X POST "$TALOS_URL/v2alpha1/admin/issuedApiKeys/${KEY_ID}:rotate" \
-H "Content-Type: application/json" \
-d '{
"scopes": ["read", "write", "admin"],
"update_mask": {"paths": ["scopes"]}
}')
echo "$RESPONSE" | jq .
export API_SECRET=$(echo "$RESPONSE" | jq -er '.secret')
export KEY_ID=$(echo "$RESPONSE" | jq -er '.key_id')
Rotation response
The response includes the new issued_api_key (with a new key_id), the new secret (shown once), and old_issued_api_key
(status KEY_STATUS_REVOKED). For the complete field reference, see the
RotateIssuedAPIKey API reference.
Zero-downtime rotation
The :rotate endpoint revokes the old key immediately. For zero-downtime rotation:
- Issue a new key with
POST /v2alpha1/admin/issuedApiKeys - Deploy the new secret to all services
- Verify the new secret works everywhere
- Revoke the old key with
POST /v2alpha1/admin/apiKeys/{old_key_id}:revoke
Revoke a key
Revocation is irreversible. Once revoked, the key fails verification immediately (subject to cache TTL):
- CLI
- curl
talos keys revoke "$KEY_ID" --reason superseded -e "$TALOS_URL"
curl -s -X POST "$TALOS_URL/v2alpha1/admin/apiKeys/${KEY_ID}:revoke" \
-H "Content-Type: application/json" \
-d '{"reason": "REVOCATION_REASON_SUPERSEDED"}'
echo ""
echo "Key revoked"
Revocation reasons
Standard reasons include REVOCATION_REASON_KEY_COMPROMISE, REVOCATION_REASON_SUPERSEDED,
REVOCATION_REASON_AFFILIATION_CHANGED, and REVOCATION_REASON_PRIVILEGE_WITHDRAWN (admin only). For the complete list, see the
RevokeAPIKey API reference.
When using PRIVILEGE_WITHDRAWN, you can include a reason_text field with a human-readable explanation.
Revocation and caching
Revocation takes effect in the database immediately. However, if caching is enabled, previously cached verification results may
remain valid until the cache entry expires. To force immediate effect, use the Cache-Control: no-cache header on verification
requests.
Verify after revocation
Confirm the key is no longer valid:
- CLI
- curl
talos keys verify "$API_SECRET" --no-cache -e "$TALOS_URL" || true
curl -s -X POST "$TALOS_URL/v2alpha1/admin/apiKeys:verify" \
-H "Content-Type: application/json" \
-H "Cache-Control: no-cache" \
-d "{\"credential\":\"$API_SECRET\"}" | jq .
Next steps
- Self-revocation -- let key holders revoke their own keys
- Issue and verify -- create new keys to replace revoked ones
- Error handling -- handle revocation-related errors
