{ tokens, solutions } pair could resubmit it as many times as they like until the token expires — bypassing the entire proof-of-work requirement. Ribaunt addresses this by tracking consumed token IDs (jti values) and rejecting any token that has already been seen.
Replay prevention modes
Ribaunt supports three modes for replay prevention, configured via thereplayPrevention option on verifySolution().
Local mode (default)
Local mode requires no configuration. When you callverifySolution() without a replayPrevention option, Ribaunt automatically uses a process-local Map to record consumed jti values. Any attempt to submit the same token twice within the same process is rejected.
Remote mode for distributed deployments
If your application runs across multiple Node.js instances, uses serverless functions, or deploys to edge workers, each process has its own memory. Local mode cannot share state between them, which means a token consumed by one instance can be replayed against any other instance. In these cases you needremote mode.
With remote mode you provide a replayStore object that implements the ReplayStore interface. Ribaunt calls replayStore.consume(jti, expiresAt) for every verified token. Your implementation is responsible for the atomic “mark as used” operation — the standard pattern with Redis or Valkey is SET NX EX (set if not exists, with an expiry).
expiresAt value is a Unix timestamp in seconds — pass it directly as the TTL for your cache key so that entries expire automatically and you do not accumulate stale data.
Disabling replay protection
If you previously relied on the old behavior whereverifySolution() had no replay checks, you can restore that behavior explicitly while you migrate:
ReplayStore interface
When usingremote mode, your replayStore must satisfy the following interface:
Return
true to allow the verification to proceed (this is the first time this token has been seen). Return false to reject it as a replay. The operation must be atomic — use a single Redis SET NX EX command rather than a separate check-then-set to avoid race conditions under concurrent load.