Home

Awesome

chillerlan/php-authenticator

A generator for counter based (RFC 4226) and time based (RFC 6238) one time passwords (OTP). (a.k.a. Yet Another Google Authenticator Implementation!)

PHP Version Support version License GitHub actions workflow Coverage Codacy Downloads

Documentation

Requirements

Installation

requires composer

via terminal: composer require chillerlan/php-authenticator

composer.json

{
	"require": {
		"php": "^8.2",
		"chillerlan/php-authenticator": "dev-main"
	}
}

Note: replace dev-main with a version constraint, e.g. ^5.0 - see releases for valid versions

Profit!

Usage

Create a secret

The secret is usually being created once during the activation process in a user control panel. So all you need to do there is to display it to the user in a convenient way - as a text string and QR code for example - and save it somewhere with the user data.

use chillerlan\Authenticator\{Authenticator, AuthenticatorOptions};

$options = new AuthenticatorOptions;
$options->secret_length = 32;

$authenticator = new Authenticator($options);
// create a secret (stored somewhere in a *safe* place on the server. safe... hahaha jk)
$secret = $authenticator->createSecret();
// you can also specify the length of the secret key, which overrides the options setting
$secret = $authenticator->createSecret(20);
// set an existing secret
$authenticator->setSecret($secret);

A secret created with Authenticator::createSecret() will also be stored internally, so that you don't need to provide the secret you just created on follow-up operations with the current instance.

Verify a one time code

Now during the login process - after the user has successfully entered their credentials - you would ask them for a one time code to check it against the secret from your user database.

// verify the code
if($authenticator->verify($otp)){
	// that's it - 2FA has never been easier! :D
}

time based (TOTP)

Verify adjacent codes

// try the first adjacent
$authenticator->verify($otp, time() - $options->period); // -> true
// try the second adjacent, default is 1
$authenticator->verify($otp, time() + 2 * $options->period); // -> false
// allow 2 adjacent codes
$options->adjacent = 2;
$authenticator->verify($otp, time() + 2 * $options->period); // -> true

counter based (HOTP)

// switch mode to HOTP
$options->mode = AuthenticatorInterface::HOTP;
// user sends the OTP for code #42, which is equivalent to
$otp = $authenticator->code(42); // -> 123456
// verify [123456, 42]
$authenticator->verify($otp, $counterValueFromUserDatabase) // -> true

URI creation

In order to display a QR code for a mobile authenticator you'll need an otpauth:// URI, which can be created using the following method.

$uri = $authenticator->getUri($label, $issuer);

// -> otpauth://totp/my%20label?secret=NKSOQG7UKKID4IXW&issuer=chillerlan.net&digits=6&period=30&algorithm=SHA1

Notes

Keep in mind that several URI settings are not (yet) recognized by all authenticators. Check the Google Authenticator wiki for more info.

// code length, currently 6 or 8
$options->digits = 8;
// valid period between 15 and 60 seconds
$options->period = 45;
// set the HMAC hash algorithm
$options->algorithm = AuthenticatorInterface::ALGO_SHA512;

API

Authenticator

methodreturndescription
__construct(SettingsContainerInterface $options = null, string $secret = null)-
setOptions(SettingsContainerInterface $options)Authenticatorcalled internally by __construct()
setSecret(string $secret)Authenticatorcalled internally by __construct()
getSecret()string
createSecret(int $length = null)string$length overrides AuthenticatorOptions setting
code(int $data = null)string$data may be a UNIX timestamp (TOTP) or a counter value (HOTP)
verify(string $otp, int $data = null)boolfor $data see Authenticator::code()
getUri(string $label, string $issuer, int $hotpCounter = null, bool $omitSettings = null)string

AuthenticatorOptions

Properties

propertytypedefaultalloweddescription
$digitsint66 or 8auth code length
$periodint3015 - 60validation period (seconds)
$secret_lengthint20>= 16length of the secret phrase (bytes, unencoded binary)
$algorithmstringSHA1SHA1, SHA256 or SHA512HMAC hash algorithm, see AuthenticatorInterface::HASH_ALGOS
$modestringtotptotp, hotp, battlenet or steamauthenticator mode: time- or counter based, see AuthenticatorInterface::MODES
$adjacentint1>= 0number of allowed adjacent codes
$time_offsetint0*fixed time offset that will be added to the current time value
$useLocalTimebooltrue*whether to use local time or request server time
$forceTimeRefreshboolfalse*whether to force refreshing server time on each call

AuthenticatorInterface

Methods

methodreturndescription
setOptions(SettingsContainerInterface $options)AuthenticatorInterface
setSecret(string $encodedSecret)AuthenticatorInterface
getSecret()string
createSecret(int $length = null)string
getServertime()int
getCounter(int $data = null)intinternal
getHMAC(int $counter)stringinternal
getCode(string $hmac)intinternal
getOTP(int $code)stringinternal
code(int $data = null)string
verify(string $otp, int $data = null)bool

Constants

constanttypedescription
TOTPstring
HOTPstring
STEAM_GUARDstring
ALGO_SHA1string
ALGO_SHA256string
ALGO_SHA512string
MODESarraymap of mode -> classname
HASH_ALGOSarraylist of available hash algorithms
<p align="center"> <a href="https://twofactorauth.org"> <img alt="2FA ALL THE THINGS!" src="https://raw.githubusercontent.com/chillerlan/php-authenticator/main/.github/images/2fa-all-the-things.jpg"> </a> </p>