Skip to main content
ZombieMutex

30 results · ↑ ↓ navigate · Enter open · Esc close

All writing
November 6, 20262 min read

Refresh-token rotation under concurrent replay: 200 scheduled callers

I sent 200 scheduled refresh attempts through one local token family. Only one issued a successor; multiple workers would need a different test.

By

Share

Send this article to someone or copy its link.

Suggest a correction

Reader tools

2 min remaining · 0% of article

Select a passage and choose Highlight selection to save it. Local browser storage only. Shift+F toggles focus.

I implemented a single-process token-family state machine and drove 200 scheduled refresh attempts against the same credential. The invariant was simple: one accepted rotation, one successor and explicit handling for every competing replay.

The handler stores SHA-256 digests of high-entropy token bytes and tracks active, consumed, expired, and revoked states. One attempt issued the successor; the others couldn't reuse the same credential. That result is useful for checking my state transitions, but it doesn't prove atomic rotation across independent servers. The code is a reference experiment, not a production identity service.

Test setup

One local session family begins with a single valid refresh token. The test schedules 200 Promise callbacks, each attempting to rotate the same token.

I ran npm test locally. The source repository is private; the central assertion is included here so the claim is checkable.

The important assertion is simple:

typescript
const replies = await Promise.all(
  Array.from({length: 200}, () =>
    Promise.resolve().then(() => service.rotate("alice", token))
  )
);

assert.equal(replies.filter(reply => reply.ok).length, 1);

Observed local outcomes

ConditionLocal test observation
200 scheduled uses of one tokenOne successor accepted
Reuse of consumed tokenRejected as replay
Explicit family revocationBlocks active and previously used credentials
Expired family tokenRotation denied
Duplicate family creationRejected

Five repository tests passed under Node.js 24.21 on macOS. These are reproducible logical outcomes, not evidence of cross-region atomicity or hardened production account recovery.

The trust boundary

The code runs within one process. Synchronous consume-and-replace operations are serialized by the JavaScript runtime, so the test is intentionally incapable of reproducing a database-level lost-update race across two independent server processes. Treat its result as an assertion about a local state machine, not a service-level availability or security guarantee.

Real production token families require durable atomic updates, expiration and key lifecycle handling, issuer/audience validation where relevant, explicit theft-detection policy, service-wide revocation, and protected recovery flows. Do not log raw refresh tokens or accept client-reported session state as authorization.

The session state-machine guide covers recovery bypasses that a simple token-rotation function does not address.


Editorial note: I used AI assistance while preparing this reference experiment. I verified the described results with local tests; they do not measure a multi-worker production identity service.

Related technical notes with overlapping topics.

Discuss a passage

Select a paragraph above, copy it with its article link, then paste into the discussion. Don't include private data.

Jump to discussion ↓

Public conversation / GitHub Discussions

Discuss this article

Read and reply using GitHub Discussions. A GitHub account is needed to post. Comments are public and subject to GitHub moderation.

For privacy, the external giscus widget does not load until you choose to open it. Opening it connects your browser to giscus and GitHub. Do not post credentials or private project data.