Small OTP library
  • PHP 99.3%
  • Makefile 0.7%
Find a file
François Kooman 4c5b011509
Some checks failed
/ tests (push) Has been cancelled
make more classes readonly
2026-06-30 12:59:10 +02:00
.forgejo/workflows various code cleanups, add CI, update psaml.xml.dist 2025-01-27 13:17:03 +01:00
example source formatting, require PHP >= 8.2 2025-04-02 08:22:43 +02:00
src make more classes readonly 2026-06-30 12:59:10 +02:00
tests update for php >= 8.4 2026-06-30 12:38:55 +02:00
.gitignore pull fkooman/otp-verifier in the 21st century 2022-01-27 17:23:38 +01:00
.php-cs-fixer.dist.php update for php >= 8.4 2026-06-30 12:38:55 +02:00
CHANGES.md prepare for release 2025-04-02 12:27:31 +02:00
composer.json update for php >= 8.4 2026-06-30 12:38:55 +02:00
LICENSE update README, LICENSE 2026-06-30 12:40:28 +02:00
Makefile update for php >= 8.4 2026-06-30 12:38:55 +02:00
phpstan.neon.dist update for php >= 8.4 2026-06-30 12:38:55 +02:00
phpunit.xml.dist readd phpunit.xml.dist 2026-06-30 12:39:25 +02:00
psalm.xml.dist require PHP >= 8.3, enable vimeo/psalm for unit tests 2025-06-16 16:48:59 +02:00
README.md update README, LICENSE 2026-06-30 12:40:28 +02:00

Summary: Small OTP verification library

Description: PHP library to verify OTP codes and protect against replay and brute force attacks.

License: MIT

Introduction

PHP library to verify OTP codes and protect against replay and brute force attacks with support for PHP >= 8.2.

What

This is a library that includes TOTP verification and protection against replay and brute force attacks.

Why

High quality OTP verification libraries exist, e.g. christian-riesen/otp and spomky-labs/otphp which are popular and work well, however, they lack built-in support for protection against replay attacks and brute force attempts.

Features

  • Supports PHP >= 8.2;
  • Verifies TOTP codes;
  • Protects againts replay attacks by storing the (used) OTP keys;
  • Protects against brute force attacks by limiting the number of attempts in a certain time frame.

Database

A database is needed to store OTP secrets and used OTP keys. Currently only SQLite is tested, but others may work.

<?php 

$storage = new fkooman\OTP\DBStorage(new PDO('sqlite:/path/to/db.sqlite'));

You can call init() on the Storage object to initialize the database, do this only once, during application installation:

<?php

$storage->init();

API

Registration

A TOTP application, e.g. running on a mobile device will need to be configured with the TOTP secret and generate a valid OTP key before registration can succeed. Your application can for example generate a TOTP secret, generate a QR code and allow the user to import that in their OTP application.

Most (T)OTP applications can handle a QR code for enrollment, making it much easier for users to configure their application. This library can generate a Key-URI to make this easier with all the right parameters set:

<?php

$userId = 'foo';
$otpInfo = fkooman\OTP\OTPInfo::create();
$keyUri = KeyURI::generate($userId, 'My Service', $otpInfo);

This will return something like this:

otpauth://totp/My%20Service:foo?secret=RMO6LYUJPDMRZTCA5JKP4TOLRYKHBF2H&algorithm=SHA1&digits=6&period=30&issuer=My%2520Service

Use this URI in a QR code and show it to the user. Once you get back a valid OTP key from the user, e.g. entered in a form, you can complete the registration:

$otp = new OTP($storage);
$otpKey = '123456';
$otp->register($userId, $otpInfo, $otpKey);

Validation

$userId = 'foo';
$otpKey = '234567';
try {
    $otp->validate($userId, $otpKey);
    echo 'VALID';
} catch (fkooman\OTP\Exception\OTPException $e) {
    echo 'ERROR: '.$e::class.PHP_EOL;
}

You can catch the specific OTP Exception for a particular case, e.g. you can catch:

Exception When?
InvalidOTPException The user provided an invalid OTP code
ReplayOTPException An OTP code was reused, i.e. "replayed"
TooManyAttemptsOTPException Too many (invalid) attempts were made

"Too many" in this case means, 10 invalid OTP codes in a row.

NOTE: you can not reuse the OTP key used for registration for verification afterwards. You have to wait for the next window, i.e. up to 30 seconds by default.

Inspiration

This library was inspired by other software, both in idea and sometimes code. A list:

License

MIT.

Contributions

We are interested in receiving small contributions that fix bugs or solve security issues. For new features, feel free to "fork" this project. If your changes are of potential interest to others you can let us know so we can link to your fork and/or merge your changes.

Contributions, including bug reports, for which LLMs i.e. "genAI" were used, or were involved in any way, are never acceptable.

Contact

You can contact me with any questions or issues regarding this project. Drop me a line at fkooman@tuxed.net.