From 15f5bc412c975cd37cd445d3e1a37986e2efa59b Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 10 Jul 2026 04:32:46 -0400 Subject: [PATCH] docs(inbound-api): dual-key API-key rotation procedure (create -> migrate -> disable -> delete) Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj --- docs/requirements/Component-InboundAPI.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/requirements/Component-InboundAPI.md b/docs/requirements/Component-InboundAPI.md index be1854a7..c861f914 100644 --- a/docs/requirements/Component-InboundAPI.md +++ b/docs/requirements/Component-InboundAPI.md @@ -72,6 +72,15 @@ Each API method definition includes: - When both headers are present, `Authorization` takes precedence. - Both forms are processed by the same `IApiKeyVerifier` from the shared `ZB.MOM.WW.Auth.ApiKeys` library; the verifier strips the optional `Bearer ` prefix and performs the same peppered-HMAC constant-time verification regardless of which header was used. +### Key rotation + +The `sbk__` design already supports zero-downtime rotation — a caller can hold two valid keys at once, so there is no moment where the old key must be cut off before the new one works. The procedure: + +1. **Create a new key** with the same scope set as the key being rotated — `security api-key create --name --methods ` (CLI `security api-key` group). Scopes are **copied at creation only**: the operator must pass the same `--methods` list the old key was approved for; the CLI does not read the old key's scopes for you, so scope drift between the pair is an operator error, not something the system detects. +2. **Deliver the new token to the caller and confirm cutover.** The response from `create` surfaces the one-time bearer token (`PrintCreatedKey` — it is shown once and cannot be retrieved again, so capture it immediately). Both the old and new keys verify successfully during this window — that overlap is intended, not a bug, and gives the caller time to redeploy with the new token without a synchronized flag-day cutover. Confirm the caller has actually switched by checking the audit log's Actor field (recorded per call), which shows which key ID is serving live traffic. +3. **Disable — don't delete — the old key** once cutover is confirmed: `security api-key update --key-id --enabled false`. Disabling is reversible (`--enabled true` re-enables it) if the cutover needs to be rolled back, whereas deletion is not. +4. **Delete the old key after a quarantine period** (an operator-judgment window to be sure nothing is still presenting the old token): `security api-key delete --key-id `. + ### Request Format - Content-Type: `application/json`. - Parameters are top-level JSON fields in the request body matching the method's parameter definitions: