Simple but Secure OTP solution!

4.0 2024-04-26 08:30 UTC

README

Codacy Badge Libraries.io dependency status for GitHub repo Packagist Downloads (custom server) License: MIT Packagist Version Packagist PHP Version GitHub code size in bytes

Simple but Secure Generic OTP, TOTP (RFC6238), HOTP (RFC4226) solution!

Prerequisites

Language: PHP 8.2/+

Library Version PHP Version
3.x.x/+ 8.2.x or Higher
2.x.x 8.x.x
1.x.x 7.x.x

Installation

composer require infocyph/otp

Why this library?

TOTP & HOTP

  • Uses offline QR code generator (no more exposing your secret online)
  • Time-safe Base32 encoding (30 seconds validity means 30 seconds)

Generic OTP

  • No need to dedicate extra storage/db for User information (just build a unique signature)

Usage

HOTP (RFC4226)

/**
* Generate Secret
* It will generate secure random secret string
*/
$secret = \Infocyph\OTP\HOTP::generateSecret();

/**
* Get QR Code Image for secret $secret
*/
// supports digit count in 2nd parameter, recommended to be either 6 or 8 (default 6)
(new \Infocyph\OTP\HOTP($secret))
// only required if the counter is being imported from another system or if it is old, & for QR only
->setCounter(3)
// default is sha1; Caution: many app (in fact, most of them) have algorithm limitation
->setAlgorithm('sha256') 
// or `getProvisioningUri` just to get the URI
->getProvisioningUriQR('TestName', 'abc@def.ghi'); 

/**
* Get current OTP for a given counter
*/
$counter = 346;
$otp = (new \Infocyph\OTP\HOTP($secret))->getOTP($counter);

/**
* Verify
*/
(new \Infocyph\OTP\HOTP($secret))->verify($otp,$counter);

TOTP (RFC6238)

/**
* Generate Secret
* It will generate secure random secret string
*/
$secret = \Infocyph\OTP\TOTP::generateSecret();

/**
* Get QR Code Image for secret $secret
*/
// supports digit count in 2nd parameter, recommended to be either 6 or 8 (default 6)
(new \Infocyph\OTP\TOTP($secret)) 
// default is sha1; Caution: many app (in fact, most of them) have algorithm limitation
->setAlgorithm('sha256') 
// or `getProvisioningUri` just to get the URI
->getProvisioningUriQR('TestName', 'abc@def.ghi');

/**
* Get current OTP
*/
$otp = (new \Infocyph\OTP\TOTP($secret))->getOTP();
// or get OTP for another specified epoch time
$otp = (new \Infocyph\OTP\TOTP($secret))->getOTP(1604820275);

/**
* Verify
* 
* on 3rd parameter it supports, enabling leeway.
* if enabled, it will also check with last segment's generated otp 
*/
(new \Infocyph\OTP\TOTP($secret))->verify($otp);
// or verify for a specified time
(new \Infocyph\OTP\TOTP($secret))->verify($otp, 1604820275);

Generic OTP

/**
* Initiate 
* Param 1 is OTP length (default 6)
* Param 2 is validity in seconds (default 30)
* Param 3 is retry count on failure (default 3)
*/
$otpInstance = new \Infocyph\OTP\OTP(4, 60, 2);

/**
* Generate & get the OTP
*/
$otp = $otpInstance->generate('an unique signature for a cause');

/**
* Verify the OTP
* 
* on 3rd parameter setting false will keep the record till the otp is verified or expired
* by default it will keep the record till the key name match or the otp is verified or expired
*/
$otpInstance->verify('an unique signature for a cause', $otp);

/**
* Delete the record
*/
$otpInstance->delete('an unique signature for a cause');

/**
* Flush all the existing OTPs (if any)
*/
$otpInstance->flush()

Note: Generic OTP uses temporary location for storage, make sure you have proper access permission

Support

Having trouble? Create an issue!