krixon / multi-factor-auth
Multi-factor authentication library for PHP7
Installs: 2 119
Dependents: 0
Suggesters: 0
Security: 0
Stars: 4
Watchers: 4
Forks: 0
Open Issues: 2
Requires
- php: >=7.2
Requires (Dev)
- ext-curl: >=7.2
- php-coveralls/php-coveralls: ^2.1
- php-mock/php-mock-phpunit: ^2.3
- phpunit/phpunit: ^8.1.0
This package is auto-updated.
Last update: 2024-10-19 22:13:32 UTC
README
A library for generating and verifying the codes used in multi-factor authentication systems.
Features:
- Time-based (TOTP) code generation and verification.
- Event-based (HOTP) code generation and verification.
- Barcode generation for easy client setup.
This library implements the following RFCs:
- RFC4226 - HOTP: An HMAC-Based One-Time Password Algorithm
- RFC6238 - TOTP: Time-Based One-Time Password Algorithm
It has been tested against the following multi-factor authentication tools:
- Google Authenticator (TOTP + HOTP)
- Authy (TOTP + HOTP)
Prerequisites
- PHP 7.1+
Installation
Install via composer
To install this library with Composer, run the following command:
$ composer require krixon/multi-factor-auth
You can see this library on Packagist.
Install from source
# HTTP $ git clone https://github.com/krixon/multi-factor-auth.git # SSH $ git clone git@github.com:krixon/multi-factor-auth.git
Quick Start
Let's say you have a server side application which you want to protect using multi-factor authentication.
There are three main steps involved:
- Generate a secret which is shared between the server and the user.
- Configure a client application (such as Google Authenticator) with the shared secret.
- Verify codes generated by the client application whenever the user needs to authenticate.
This library makes these steps easy.
The quickest way to get up and running is to create a new instance of the MultiFactorAuth
class. This takes
various arguments to its constructor, but there is a static factory provided which creates an instance with sensible
and secure defaults. The only thing you need to provide is an "issuer" string. This is just a label which
identifies the provider or service managing a user's account - i.e. your application.
<?php use Krixon\MultiFactorAuth\MultiFactorAuth; $mfa = MultiFactorAuth::default('Example Issuer');
Next you need to generate the shared secret. By default the code below will generate a 160-bit, base32-encoded string:
$secret = $mfa->generateSecret();
In order for the user to configure their client application, they need to enter the secret that was just generated. Often the user's client application will be running on their mobile phone. Entering a 160-bit secret by hand is certainly possible, but we can make it easier by providing the user with a barcode to scan. This barcode contains all of the information required to configure the client.
When generating a barcode you must also provide an account identifier. This can be any string which allows the user to distinguish between multiple accounts in their client application. A good value for this is the user's email address.
$barcode = $mfa->generateTimeBasedBarcode($secret, 'jane.doe@example.com');
The generateTimeBasedBarcode()
method returns a Barcode
instance. This can be used to ultimately render the
image, for example on a webpage:
<img src="<?= $barcode->dataUri() ?>">
Once the user has scanned the barcode, they should be prompted to enter a code which can be verified to determine that the configuration process was successful.
$verified = $mfa->verifyTimeBasedCode($code, $secret);
If the code is verified successfully, the secret can be securely persisted on the server, for example in a database.
From now on, when the user authenticates they should be prompted to enter a code along with their other credentials such as username and password. This code should be verified using the stored shared secret and authentication denied if verification fails.
Generating Backup Codes
If a user loses their device or otherwise cannot generate codes, you can allow them to login via a pre-generated backup code. Event-based (HOTP) codes are perfect for this.
The following example generates 10 backup codes which the user can write down or otherwise store.
use Krixon\MultiFactorAuth\Codec\Base32Codec; use Krixon\MultiFactorAuth\MultiFactorAuth; $mfa = MultiFactorAuth::default('Test Issuer'); // Secrets are expected to be in base32 by default for compatibility with Google Authenticator and similar apps. // It is possible to use any encoding (including none). See below for more information. $secret = (new Base32Codec())->encode('12345678901234567890'); // Retrieve the real counter from the DB or wherever it is stored. $counter = 42; // $codes is an array of 10 strings, each 6 digits long. $codes = $mfa->generateBackupCodes($secret, $counter, 10, 6); foreach ($codes as $code) { // Do something with the backup code. // Generally you would salt and hash the code and store it in a database. These codes would be checked // against the one entered by the user (in addition to checking the current time or event-based code). echo "$code\n"; }
Generating Secrets
By default, secrets are generated using the RandomBytesSecretGenerator
. This generates cryptographically secure
secrets using PHP's random_bytes
function. If a different method is required, simply implement the
SecretGenerator
interface.
The RandomBytesSecretGenerator
takes a Codec
instance which determines how generated secrets are encoded. For
maximum compatibility with Google Authenticator and similar apps, secrets should be base32 encoded, so the
Base32Codec
is used if no alternative is specified.
To generate a secret, either use a SecretGenerator
directly, or use the MultiFactorAuth
facade.
$generator = new RandomBytesSecretGenerator(); // Generates a base32-encoded, 20 byte random secret. $secret = $generator->generateSecret(); // Generates a base32-encoded, 30 byte random secret. $secret = $generator->generateSecret(30); // Generates a raw binary, 20 byte random secret. $generator = new RandomBytesSecretGenerator(new PassThroughCodec()); $secret = $generator->generateSecret(30); // Generates a base32-encoded, 20 byte random secret. $mfa = MultiFactorAuth::default('Test Issuer'); $secret = $mfa->generateSecret();
Sandbox
There is a simple sandbox script in the examples
directory which can be used to generate secrets and barcodes and
to verify codes generated by a client application.
The sandbox can be run with the PHP built-in webserver. Make sure to specify the correct path to the examples
directory:
php -S localhost:8080 -t /path/to/krixon/multi-factor-auth/examples
You can now visit http://localhost:8080/sandbox.php to use the sandbox.
TODO
- More automated tests.
- Expand documentation.
- Verify support for RFC6287 - OCRA: OATH Challenge-Response Algorithm.