Replay Protection#
Overview#
Replay protection is intentionally pluggable.
Available contract:
Infocyph\OTP\Contracts\ReplayStoreInterface
Included store:
Infocyph\OTP\Stores\InMemoryReplayStore
Recommended policy#
TOTP#
Store the last accepted timestep per user or device binding.
Reject the same timestep once accepted.
HOTP#
Store the last accepted counter.
Reject already-used counters.
Persist any resynchronized counter once accepted.
OCRA#
Reject reused challenge/counter combinations where the flow requires single use.
Example#
<?php
use Infocyph\OTP\Stores\InMemoryReplayStore;
use Infocyph\OTP\ValueObjects\VerificationWindow;
$store = new InMemoryReplayStore();
$result = $totp->verifyWithWindow(
$otp,
window: new VerificationWindow(past: 1, future: 1),
replayStore: $store,
binding: 'user-42',
);
Persistent implementations#
The in-memory replay store is mainly for tests and lightweight scenarios.
See Custom Persistent Stores for a database-oriented example implementing ReplayStoreInterface.