2fa library

Latest Version Software License Build Status Coverage Status Quality Score Total Downloads

This library allows developers to implement Time Based One Time Passwords (TOTP) for the PHP implementation of the 2factor Authentication (2FA), supporting both the HMAC-based one-time password (HOTP) and the time-based one-time passwords (TOTP).

Getting Started

The preferred way to install this extension is through composer.

Either run

php composer.phar require 2amigos/2fa-library:^2.0

or add

    "2amigos/2fa-library": "^2.0"

Usage

How to generate a secret key

The secret key requires to be saved to later check with the input key from the user to implement the two-factor authentication (2FA).

This is how you create a secret key:

use Da\TwoFA\Manager;

$secret = (new Manager())->generateSecretKey();

How to use two-factor authentication

The first thing you need to do is to generate the secret key for your user before is saved.

use Da\TwoFA\Manager;

$manager = new Manager();

$user->twofa_secret = $manager->generateSecretKey();

Then, when user chooses to include two-factor authentication as login, you should present a QR Code to the user to scan using one of the two-factor authentication apps. There are couple of ways to display it. For example, with data-uri:

<?php 
use Da\TwoFA\Service\TOTPSecretKeyUriGeneratorService;  
use Da\TwoFA\Service\QrCodeDataUriGeneratorService;

// first we need to create our time-based one time password secret uri
$totpUri = (new TOTPSecretKeyUriGeneratorService('your-company', $user->email, $user->twofa_secret))->run();
$uri = (new QrCodeDataUriGeneratorService($totpUri))->run();
?>


<!-- display it -->
<img src="<?= $uri ?>" alt="" />

With google uri:

<?php 
use Da\TwoFA\Service\TOTPSecretKeyUriGeneratorService;
use Da\TwoFA\Service\GoogleQrCodeUrlGeneratorService;

// first we need to create our time-based one time password secret uri
$totpUri = (new TOTPSecretKeyUriGeneratorService('your-company', $user->email, $user->twofa_secret))->run();

$googleUri = (new GoogleQrCodeUrlGeneratorService($totpUri))->run();
?>
<!-- display it -->
<img src="<?= $googleUri ?>" alt="" />

Or by pointing the src attribute of the img tag to a script (or action if you use a framework) that will create the Qr Code.

When the Qr Code is presented, the user should scan it with their favorite 2FA Authenticator mobile app. Then, to verify, after user has logged in with their regular credentials you should present a new screen where user can enter the code given by its 2FA Authenticator mobile app:

use Da\TwoFA\Manager;

$manager = new Manager();

$valid = $manager->verify($_POST['key'], $user->twofa_secret);

Preventing out of sync clocks

In order to avoid sync issues between servers, we have the $cycles attribute. By default, each cycle of key generation is about 30 seconds. We can change that value by modifying the $counter attribute. If $cycles is a positive number it will increase verification times, past and future, from current time. That is, if $cycles is set to 1 (value by default), it will increase 1 more time the seconds set in $counter. If $counter is set to 30 then it will be 60. Set this attribute to 0 if you don't care about this sync issue.

use Da\TwoFA\Manager;

$manager = new Manager();

$valid = $manager
    ->setCycles(2) // 120 seconds (60 seconds past and future respectively) 
    ->verify($_POST['key'], $user->twofa_secret);

Remember that you can also modify the $counter, which defaults to 30 seconds, by the Manager::setCounter method.

Preventing insertion of a previous code

To prevent the usage of a key code more than once (in case someone has seen your code) you can include the latest time he was validated. If null is provided, the method verify will return a boolean value, but if we pass a timestamp value, it will return a timestamp value that we can safe for future verifications.

use Da\TwoFA\Manager;

$manager = new Manager();

$previousTs = $user->twofa_timestamp ? : $manager->getTimestamp();

$timestamp = $manager->verify($_POST['key'], $user->twofa_secret, $previousTs);

if($timestamp) { 
    // ... success, update user timestamp
    $user->twofa_timestamp = $timestamp; 
    $user->save();
} else {
    // ... error
}

Bigger keys & prefixing secret keys

You can harden the collision probabilities of the random string by incrementing the length of the secret keys:

use Da\TwoFA\Manager;

$manager = new Manager();

$user->twofa_secret = $manager->generateSecretKey(32); 

By prefixing keys, we need to remember that all keys must have length in power of 2. So, if the key is 16 bytes long, your prefix string must be also 16 bytes long. But as the prefixes will be converted to Base32, the maximum length of that prefix is 10 bytes. Therefore, the sizes of your prefixes would be: 1, 2, 5, 10, 20, 40, 80 ..., and it can be used like:


use Da\TwoFA\Manager;

$manager = new Manager();

$prefix = strpad($id, 10, 'X');

$secretKey = $manager->generateSecretKey(16, $prefix);

Google Authenticator compatibility

To be compatible with Google Authenticator, your (converted to base 32) secret key length must be at least 8 chars and be a power of 2: 8, 16, 32, 64... This is why the library forces you to create the secret key throughout its Manager::generateSecretKey() or Encoder::generateBase32RandomKey() methods. You should only be concerned about the prefix as stated previously.

By default, the library enforces google compatibility, but if Google Authenticator is not a target, you can disable it like this:

<?php 
use Da\TwoFA\Manager;
use Da\TwoFA\Validator\SecretKeyValidator;

$validator = new SecretKeyValidator(false);
$manager = new Manager(false);
?>

or:

<?php 
use Da\TwoFA\Manager;

$manager = (new Manager())->disableGoogleAuthenticatorCompatibility();
?>

IMPORTANT: Server Time

It's very important to keep the server time in sync with an NTP server.

Credits

This library is highly inspired by the excellent work of Antonio Ribeiro. This library is a different approach of what he did, and therefore deserves all the credit of this one. The reason to create our very own version, was no other that to have full control of updates and fixes and provide a different version of what he did, as we are going to implement it on our other library yii-usuario.

If you wish to check his library, please visit:

© 2amigos 2013-2020