Skip to content

fix(oauth): rotate the api key alongside a shared pre-split client secret - #61

Merged
matthew-demidoff merged 1 commit into
masterfrom
fix/api-key-rotation
Aug 20, 2026
Merged

fix(oauth): rotate the api key alongside a shared pre-split client secret#61
matthew-demidoff merged 1 commit into
masterfrom
fix/api-key-rotation

Conversation

@matthew-demidoff

@matthew-demidoff matthew-demidoff commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Apps created before the api-key/client-secret split (78137a0) share one hash across api_key_hash and oauth_client_secret_hash; migration 005 coalesced them and nothing backfilled. Rotating the client secret therefore left the outgoing secret valid as an api key on /api/activation-requests and /api/authorizations indefinitely, and no api key rotation path existed at all.

  • rotate_secret now co-rotates the api key when the app's credential is shared. Sharing is detected in SQL as hash equality or a matching row in external_app_oauth_secrets - the grace-table check covers pre-split apps that already rotated their secret before this fix (their shared hash moved to the grace table while api_key_hash kept holding it, so plain equality misses them).
  • The api key rotates first, so a mid-sequence failure leaves the shared state intact and a retry still co-rotates.
  • New standalone Rotate API key action + danger-zone row. Immediate cutover, no grace window: rotation here is compromise response.
  • Rotation refreshes any unrevealed bearer_requests.plaintext_key so a pending one-time reveal hands out the new key instead of a dead one.

Review attention: the co-rotation decision lives in findExternalAppSecretHashForOwner's api_key_shared_with_oauth SQL; the OAuth surface keeps its existing 7-day grace for the outgoing secret by design, so a leaked shared secret dies immediately as an api key but stays valid as an OAuth secret for the grace period.

…cret

Apps created before the api-key/client-secret split (78137a0) share one
hash across api_key_hash and oauth_client_secret_hash, so rotating the
client secret left the outgoing secret valid as an api key forever.
Rotating the secret on such an app now rotates the api key in the same
action, and the danger zone gains a standalone api key rotation (no
rotation path existed for api keys at all). Api key cutover is
immediate; the OAuth surface keeps its 7-day grace window.
@matthew-demidoff
matthew-demidoff merged commit 1761351 into master Aug 20, 2026
2 checks passed
@matthew-demidoff
matthew-demidoff deleted the fix/api-key-rotation branch August 20, 2026 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant