PHP implementation of RFC 4226 and RFC 6238. Generates one-time passwords.
Provides a ready-to-use TOTP class for easy integration with authenticator apps along with an extensible HOTP class for custom one-time password implementations.
composer require covaleski/otp
The Totp
class can be used to:
- Emit codes;
- Validate received codes;
- Create URIs for QR code generation.
Authenticator QR codes are just the OTP URIs encoded as a QR code. Follow the steps below to create the URI.
use Covaleski\Otp\Totp;
// Define some settings.
$digits = 6;
$issuer = 'Foobar Inc.';
$label = 'Foobar: john@foobar.com';
// Create a secret.
$secret = '1234';
// Instantiate the TOTP class and get the URI.
$totp = new Totp($digits, $issuer, $label, $secret);
$uri = $totp->getUri();
You can output the URI as a QR code using any library of your choice.
Use getPassword()
to get the current code.
use Covaleski\Otp\Totp;
// Instantiate the TOPT class.
$digits = 6;
$totp = new Totp(6, 'Cool LLC', 'Cool: john@cool.com', $secret);
// Get the current password.
$input = (string) $_POST['code'];
$is_valid = $totp->getPassword() === $input;
echo 'Your code is ' . ($is_valid ? 'correct!' : 'incorrect!');
You can change several parameters of your generator. The example below creates a TOTP object that:
- Outputs 8-digit codes;
- Change the code every 15 seconds;
- Calculates the code with a time offset of 1 hour.
use Covaleski\Otp\Totp;
// Instantiate and configure.
$totp = new Totp(8, $issuer, $label, $secret);
$totp
->setStep(15)
->setOffset(3600);
Note that some implementations may ignore or even reject one or more custom TOTP parameters. The most compatible configuration (usually) is to generate 6-digit codes every 30 seconds with no time offset.
You can extend the Covaleski\Otp\Hotp
to create your own one-time password implementation.
Extensions must provide two methods: getCounter()
and getUri()
. The first one must output the current counter as an 8-byte binary string (e.g. a time counter), and the second is responsible for providing the integration URI.
Furthermore, the Hotp
class will do the rest and:
- Generate the HMAC-SHA-1 string;
- Dinamically truncate the HMAC binary string;
- Compute the HOTP value and output the required amount of digits.
See how the methods are implemented in the Covaleski\Otp\Totp
class:
class Totp extends Hotp
{
// ...Other class members...
/**
* Get the current time counter.
*
* Returns the counter as a 8-byte binary string.
*/
protected function getCounter(): string
{
// Get and offset the current UNIX timestamp.
$time = time() + $this->offset;
// Calculate the number of steps.
$counter = floor($time / $this->step);
// Format the number as an 8-byte binary string.
$counter = dechex($counter);
$counter = str_pad($counter, 16, '0', STR_PAD_LEFT);
$counter = hex2bin($counter);
return $counter;
}
/**
* Get the URI for authentication apps.
*/
public function getUri(): string
{
// Encode the secret as base32.
$secret = Base32::encode($this->secret);
$secret = str_replace('=', '', $secret);
// Build URI.
return $this->createUri('totp', [
'secret' => $secret,
'issuer' => $this->issuer,
'algorithm' => 'SHA1',
'digits' => $this->digits,
'period' => $this->step,
]);
}
// ...Other class members...
}
The Totp
class depends on time to create its counter and encode its secrets as base32 strings when creating the URI.
Tests were made with PHPUnit. Use the following command to run them.
./vendor/bin/phpunit