Replay protection
Concept
Even a perfectly request-bound passport could be captured and re-sent within its short
lifetime. Replay protection makes each accepted passport usable exactly once: the passport's
jti is consumed atomically on the first accepted presentation, and any repeat is denied
with jti_replay.
The key word is atomic. A naive "check if seen, then mark seen" has a race: two concurrent duplicates can both pass the check before either marks. TrustPlane uses a single consume-on-accept operation so that out of N concurrent duplicates, exactly one succeeds.
Implementation
- Lives in
pkg/authcoreas an atomicConsumeoperation (not a splitHas/Add). - Two backends:
- Memory (
memory.go) — mutex-atomic, for a single instance. - Redis (
redis.go) — usesSET NX EXso concurrent calls for the same key return exactly one success, with TTL preserved. Errors fail closed for protected paths.
- Memory (
- Multi-replica safety: running more than one replica requires the Redis store. The config validation rejects multi-replica without Redis, and the Helm chart refuses to render it.
- Ordering: replay is consumed after policy checks pass, so unauthorized junk cannot burn
a victim's
jti.
Example
The provider/gateway demo sends the same accepted request twice and shows the second denied:
make demo-provider-gateway
# ... valid call allows ...
# ... duplicate call -> { "allowed": false, "reason": "jti_replay" }
Concurrency is covered by regression tests proving only one of N concurrent duplicates succeeds,
in both the in-memory and Redis paths. These run as part of make test and the
acceptance gate.
To use Redis in a multi-replica deployment, the chart expects:
replay:
store: redis
multiReplica: true
redis:
addr: "redis.example:6379"
…and fails render if multiReplica/replicas > 1 is set with store: memory.
What to notice
- Replay protection is a safety property of acceptance, not an afterthought: it is consumed only on otherwise-valid requests, and only once.
- "Fail closed" means a Redis outage denies protected requests rather than silently allowing replays.
→ Next: Bundle policy & freshness.