Replay protection
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 Auth uses a single consume-on-accept operation so that out of N concurrent duplicates, exactly one succeeds.
How it works
Section titled “How it works”- 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.
sequenceDiagram participant C1 as Caller (request) participant C2 as Attacker (replay) participant V as Verifier participant R as Replay store (memory/Redis) C1->>V: passport + proof (jti = abc) V->>R: Consume(abc) [SET NX EX] R-->>V: success (first time) V-->>C1: allow C2->>V: same passport + proof (jti = abc) V->>R: Consume(abc) R-->>V: already present V-->>C2: deny: jti_replay
See a replay denied
Section titled “See a replay denied”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.
Configure Redis for multiple replicas
Section titled “Configure Redis for multiple replicas”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
Section titled “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 steps
Section titled “Next steps”- Bundle policy — per-route rules and fail-closed freshness from a local bundle.