04
Product
16
Backend
09
Auth
12
iOS
07
Infra
02
Real-Time

Use tokio-cron for PASETO key rotation

ADR-0026 ACCEPTED · 2025-07-24
Use tokio-cron for PASETO key rotation

Context

The application runs as a long-lived Rust/Axum server on a 3-node cluster. PASETO key rotation needs to happen automatically — generate new keys, deprecate old ones, revoke expired ones.

Decision

Use tokio-cron to schedule daily key rotation within the application process. PostgreSQL advisory locks (ADR-0022) prevent concurrent execution across nodes.

Key lifecycle: activedeprecated (365 days) → revoked

Production example

Actual data from the paseto_keys table showing the rotation cycle:

SELECT key_identifier, status, created_at, rotated_at FROM paseto_keys;

key_identifier                                        | status     | created_at                    | rotated_at
k4.lid.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | revoked    | 2025-08-12 02:00:00.003055+00 | 2025-08-19 02:00:00.004467+00
k4.lid.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | deprecated | 2025-08-19 02:00:00.004467+00 | 2025-08-26 02:00:00.005355+00
k4.lid.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | deprecated | 2025-08-26 02:00:00.005355+00 | 2025-09-02 02:00:00.009917+00
k4.lid.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | deprecated | 2025-09-02 02:00:00.009917+00 | 2025-09-09 02:00:00.006877+00
k4.lid.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | deprecated | 2025-09-09 02:00:00.006877+00 | 2025-09-16 02:00:00.006826+00
k4.lid.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | active     | 2025-09-16 02:00:00.006826+00 |

Weekly rotation at 02:00 UTC. One active key at a time, multiple deprecated keys for validating existing tokens.

Consequences

Automated key rotation without manual intervention or external schedulers. Runs within the application lifecycle. The trade-off is a new dependency and clock sensitivity — rotation fails silently if scheduling breaks, so monitoring consecutive failures matters.