Generic OTP Guide#
Generic OTP is useful when you want one-time codes without managing a dedicated OTP database table, while still keeping server-side verification state.
It is a strong fit for delivery channels such as SMS, email, and instant messaging platforms, because your application generates the code and decides how to deliver it.
When to use it#
This mode is application-oriented rather than RFC-specific. That does not limit it to any one transport. It is useful for cases like:
signup verification
SMS OTP
email OTP
OTP over chat or IM platforms
password reset codes
short-lived step-up verification codes
PSR-6 cache requirement#
The generic OTP class requires a PSR-6 cache pool implementation:
<?php
use Infocyph\OTP\OTP;
$otp = new OTP(
digitCount: 6,
validUpto: 60,
retry: 3,
hashAlgorithm: 'xxh128',
cacheAdapter: $cachePool,
);
Codes are strings#
Generated codes are strings.
Verification expects a string.
Leading zeroes are preserved.
Basic flow#
<?php
$code = $otp->generate('signup:[email protected]');
$otp->verify('signup:[email protected]', $code);
$otp->delete('signup:[email protected]');
Another example for a password reset flow:
<?php
$signature = 'password-reset:user-42';
$code = $otp->generate($signature);
// deliver $code to the user
if ($otp->verify($signature, $submittedCode)) {
// continue reset flow
}
Example for SMS or IM delivery:
<?php
$signature = 'login-otp:user-42:phone:+15551234567';
$code = $otp->generate($signature);
// send $code by SMS, WhatsApp, Telegram, or another messaging channel
if ($otp->verify($signature, $submittedCode)) {
// mark the login challenge as verified
}
Retry semantics#
The third argument of verify() controls whether a found record should be removed immediately:
<?php
$otp->verify('signup:[email protected]', $code, deleteIfFound: false);
When deleteIfFound is false, the record remains until it is verified, runs out of retries, or expires.
Data model#
The generic OTP cache payload keeps:
a hashed representation of the generated OTP
retry state
the expiration moment
Because codes are strings, leading zeroes are preserved correctly.