Repository navigation
Rotate the requestState signing key without failing the calls in flight #624
Description
Builder::setRequestState(string $key, int $ttl = 600) takes exactly one key, which both signs and verifies every requestState.
Rotating it, whether on schedule or because it leaked, fails every multi round-trip call in flight: the retry carries a state signed with the old key, and the server only knows the new one.
With several instances it is worse, because they never all switch at the same instant, so for the length of the deployment each instance refuses the states the others signed.
The 2026-07-28 specification requires servers to integrity-protect requestState when it influences authorization or business logic (Multi Round-Trip Requests, Server Requirements).
A key protecting authorization-relevant state needs a rotation story.
Proposal
Accept a key ring wherever a key is accepted today: setRequestState(string|array $key, int $ttl = 600) and new RequestStateCodec(string|array $key, ...).
- The first key signs, every key verifies.
- Each key must still be at least 32 bytes, and the ring must be a non-empty list.
- The wire format stays
base64url(payload).base64url(HMAC): a single key works as before, and a state names no key.
Rotation then becomes:
[$current, $new]on every instance, so they all accept the new key before any signs with it (a single instance can skip this).[$new, $current]: sign with the new key, still accept the old.- One TTL later,
[$new].
Key id or not
The Python SDK embeds a 4-byte key id derived from the key to pick the key in O(1).
I would leave it out here: an HMAC over a short body costs microseconds, a ring rarely holds more than two keys, and a key id changes the wire format.
That last point matters most for rotation itself, because instances still running an older SDK release could not verify states carrying a key id during a rolling upgrade.
Precedents
- Python SDK:
RequestStateSecurity(keys=[...]),keys[0]seals and every key unseals, with the same three-step rotation (request_state.py, python-sdk#3032). - TypeScript SDK: a single
keytoday (requestStateCodec.ts).
Context
Shopware (https://github.com/shopware/shopware) plans URL-mode elicitation on the 2026-07-28 era and runs multi-instance deployments, where the signing key comes from configuration and has to be rotatable without failing customers' calls in flight.
Activity