Add `grace_period` support to token regeneration
Summary
When regenerating a token via POST /v0.1/tokens/{id}/regenerate, callers can optionally specify a grace_period (in seconds) to keep the previous API key valid for a transition window. This enables seamless key rotation without downtime for clients still using the old key.
If grace_period is not provided, the previous key is immediately invalidated (current behavior preserved).
Changes
- Add
previous_api_key(encrypted) andprevious_api_key_expires_at(DateTime) nullable columns to theTokenmodel with an Alembic migration - Extend
TokenRegenerateInschema with an optionalgrace_periodfield, validated againstMAX_TOKEN_GRACE_PERIOD_SECONDS(default 30 days, configurable via dynaconf validator inconfig.pyand overridable insettings.yaml) - Update
get_token_db()to fall back toprevious_api_keylookup when the primary key match fails and the grace period hasn't expired - Block
grace_periodonTokenCreateIn(inherited fromTokenRegenerateInbut not applicable)
Design notes
- No new tables —
previous_api_keyandprevious_api_key_expires_atare inline nullable columns ontokens - At most one previous key per token — each regeneration overwrites the previous key, preventing unbounded key accumulation
- Zero overhead for normal auth — the fallback query only fires when the primary
api_keymatch fails - No cleanup needed — expired previous keys are ignored by the query filter and overwritten on next regeneration
Related MRs
Resolves: TFT-4543
Assisted-by: Claude Code
Edited by Miroslav Vadkerti