pragmarx / google2fa
A One Time Password Authentication package, compatible with Google Authenticator.
Installs: 44 480 585
Dependents: 114
Suggesters: 8
Security: 0
Stars: 1 842
Watchers: 51
Forks: 200
Open Issues: 1
Requires
- php: ^7.1|^8.0
- paragonie/constant_time_encoding: ^1.0|^2.0|^3.0
Requires (Dev)
- phpstan/phpstan: ^1.9
- phpunit/phpunit: ^7.5.15|^8.5|^9.0
- 9.x-dev
- 8.x-dev
- v8.0.3
- v8.0.2
- v8.0.1
- 8.0.0
- 7.x-dev
- v7.0.0
- v6.1.3
- v6.1.0
- v6.0.1
- v6.0.0
- v5.0.0
- v4.0.2
- v4.0.1
- v4.0.0
- v3.0.3
- v3.0.2
- v3.0.1
- v3.0.0
- dev-master / 2.0.x-dev
- v2.0.7
- v2.0.6
- v2.0.5
- v2.0.4
- v2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
- v1.0.1
- v1.0.0
- v0.8.1
- v0.8.0
- v0.7.1
- v0.7.0
- v0.6.0
- v0.5.0
- v0.1.0
- dev-reformat-code
- dev-add-linting
- dev-reorder-imports
- dev-install-php-84
- dev-test-on-php84
- dev-github-actions
- dev-pspstan
- dev-revert-124-123-google2fa_fix
This package is auto-updated.
Last update: 2024-10-20 12:45:08 UTC
README
Google Two-Factor Authentication for PHP
Google2FA is a PHP implementation of the Google Two-Factor Authentication Module, supporting the HMAC-Based One-time Password (HOTP) algorithm specified in RFC 4226 and the Time-based One-time Password (TOTP) algorithm specified in RFC 6238.
Menu
- Version Compatibility
- Google Two-Factor Authentication for PHP
- Laravel bridge
- Demos, Example & Playground
- Requirements
- Installing
- Usage
- How To Generate And Use Two Factor Authentication
- Generating QRCodes
- QR Code Packages
- Examples of Usage
- HMAC Algorithms
- Server Time
- Validation Window
- Using a Bigger and Prefixing the Secret Key
- Google Authenticator secret key compatibility
- Google Authenticator Apps
- Deprecation Warning
- Testing
- Authors
- License
- Contributing
Version Compatibility
Laravel bridge
This package is agnostic, but there's a Laravel bridge.
About QRCode generation
This package does not generate QRCodes for 2FA.
If you are looking for Google Two-Factor Authentication, but also need to generate QRCode for it, you can use the Google2FA QRCode package, which integrates this package and also generates QRCodes using the BaconQRCode library, or check options on how to do it yourself here in the docs.
Demos, Example & Playground
Please check the Google2FA Package Playground.
Here's a demo app showing how to use Google2FA: google2fa-example.
You can scan the QR code on this (old) demo page with a Google Authenticator app and view the code changing (almost) in real time.
Requirements
- PHP 7.1 or greater
Installing
Use Composer to install it:
composer require pragmarx/google2fa
To generate inline QRCodes, you'll need to install a QR code generator, e.g. BaconQrCode:
composer require bacon/bacon-qr-code
Usage
Instantiate it directly
use PragmaRX\Google2FA\Google2FA; $google2fa = new Google2FA(); return $google2fa->generateSecretKey();
How To Generate And Use Two Factor Authentication
Generate a secret key for your user and save it:
$user->google2fa_secret = $google2fa->generateSecretKey();
Generating QRCodes
The more secure way of creating QRCode is to do it yourself or using a library. First you have to install a QR code generator e.g. BaconQrCode, as stated above, then you just have to generate the QR code url using:
$qrCodeUrl = $google2fa->getQRCodeUrl( $companyName, $companyEmail, $secretKey );
Once you have the QR code url, you can feed it to your preferred QR code generator.
// Use your own QR Code generator to generate a data URL: $google2fa_url = custom_generate_qrcode_url($qrCodeUrl); /// and in your view: <img src="{{ $google2fa_url }}" alt="">
And to verify, you just have to:
$secret = $request->input('secret'); $valid = $google2fa->verifyKey($user->google2fa_secret, $secret);
QR Code Packages
This package suggests the use of Bacon/QRCode because it is known as a good QR Code package, but you can use it with any other package, for instance Google2FA QRCode, Simple QrCode or Endroid QR Code, all of them use Bacon/QRCode to produce QR Codes.
Usually you'll need a 2FA URL, so you just have to use the URL generator:
$google2fa->getQRCodeUrl($companyName, $companyEmail, $secretKey)
Examples of Usage
Google2FA QRCode
Get a QRCode to be used inline:
$google2fa = (new \PragmaRX\Google2FAQRCode\Google2FA()); $inlineUrl = $google2fa->getQRCodeInline( 'Company Name', 'company@email.com', $google2fa->generateSecretKey() );
And use in your template:
<img src="{{ $inlineUrl }}">
Simple QrCode
<div class="visible-print text-center"> {!! QrCode::size(100)->generate($google2fa->getQRCodeUrl($companyName, $companyEmail, $secretKey)); !!} <p>Scan me to return to the original page.</p> </div>
Endroid QR Code Generator
Generate the data URL
$qrCode = new \Endroid\QrCode\QrCode($value); $qrCode->setSize(100); $google2fa_url = $qrCode->writeDataUri();
And in your view
<div class="visible-print text-center"> {!! $google2fa_url !!} <p>Scan me to return to the original page.</p> </div>
Bacon/QRCode
<?php use PragmaRX\Google2FA\Google2FA; use BaconQrCode\Renderer\ImageRenderer; use BaconQrCode\Renderer\Image\ImagickImageBackEnd; use BaconQrCode\Renderer\RendererStyle\RendererStyle; use BaconQrCode\Writer; $google2fa = app(Google2FA::class); $g2faUrl = $google2fa->getQRCodeUrl( 'pragmarx', 'google2fa@pragmarx.com', $google2fa->generateSecretKey() ); $writer = new Writer( new ImageRenderer( new RendererStyle(400), new ImagickImageBackEnd() ) ); $qrcode_image = base64_encode($writer->writeString($g2faUrl));
And show it as an image:
<img src="data:image/png;base64, <?php echo $qrcode_image; ?> "/>
HMAC Algorithms
To comply with RFC6238, this package supports SHA1, SHA256 and SHA512. It defaults to SHA1, so to use a different algorithm you just have to use the method setAlgorithm()
:
use PragmaRX\Google2FA\Support\Constants; $google2fa->setAlgorithm(Constants::SHA512);
Server Time
It's really important that you keep your server time in sync with some NTP server, on Ubuntu you can add this to the crontab:
sudo service ntp stop sudo ntpd -gq sudo service ntp start
Validation Window
To avoid problems with clocks that are slightly out of sync, we do not check against the current key only but also consider $window
keys each from the past and future. You can pass $window
as optional third parameter to verifyKey
, it defaults to 1
. When a new key is generated every 30 seconds, then with the default setting, keys from one previous, the current, and one next 30-seconds intervals will be considered. To the user with properly synchronized clock, it will look like the key is valid for 60 seconds instead of 30, as the system will accept it even when it is already expired for let's say 29 seconds.
$secret = $request->input('secret'); $window = 8; // 8 keys (respectively 4 minutes) past and future $valid = $google2fa->verifyKey($user->google2fa_secret, $secret, $window);
Setting the $window
parameter to 0
may also mean that the system will not accept a key that was valid when the user has seen it in their generator as it usually takes some time for the user to input the key to the particular form field.
An attacker might be able to watch the user entering his credentials and one time key.
Without further precautions, the key remains valid until it is no longer within the window of the server time. In order to prevent usage of a one time key that has already been used, you can utilize the verifyKeyNewer
function.
$secret = $request->input('secret'); $timestamp = $google2fa->verifyKeyNewer($user->google2fa_secret, $secret, $user->google2fa_ts); if ($timestamp !== false) { $user->update(['google2fa_ts' => $timestamp]); // successful } else { // failed }
Note that $timestamp
is either false
(if the key is invalid or has been used before) or the provided key's unix timestamp divided by the key regeneration period of 30 seconds.
Using a Bigger and Prefixing the Secret Key
Although the probability of collision of a 16 bytes (128 bits) random string is very low, you can harden it by:
Use a bigger key
$secretKey = $google2fa->generateSecretKey(32); // defaults to 16 bytes
You can prefix your secret keys
You may prefix your secret keys, but you have to understand that, as your secret key must have length in power of 2, your prefix will have to have a complementary size. So if your key is 16 bytes long, if you add a prefix it must also be 16 bytes long, but as your prefixes will be converted to base 32, the max length of your prefix is 10 bytes. So, those are the sizes you can use in your prefixes:
1, 2, 5, 10, 20, 40, 80...
And it can be used like so:
$prefix = strpad($userId, 10, 'X'); $secretKey = $google2fa->generateSecretKey(16, $prefix);
Window
The Window property defines how long a OTP will work, or how many cycles it will last. A key has a 30 seconds cycle, setting the window to 0 will make the key last for those 30 seconds, setting it to 2 will make it last for 120 seconds. This is how you set the window:
$secretKey = $google2fa->setWindow(4);
But you can also set the window while checking the key. If you need to set a window of 4 during key verification, this is how you do:
$isValid = $google2fa->verifyKey($seed, $key, 4);
Key Regeneration Interval
You can change key regeneration interval, which defaults to 30 seconds, but remember that this is a default value on most authentication apps, like Google Authenticator, which will, basically, make your app out of sync with them.
$google2fa->setKeyRegeneration(40);
Google Authenticator secret key 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...
So, to prevent errors, you can do something like this while generating it:
$secretKey = '123456789'; $secretKey = str_pad($secretKey, pow(2,ceil(log(strlen($secretKey),2))), 'X');
And it will generate
123456789XXXXXXX
By default, this package will enforce compatibility, but, if Google Authenticator is not a target, you can disable it by doing
$google2fa->setEnforceGoogleAuthenticatorCompatibility(false);
Google Authenticator Apps
To use the two factor authentication, your user will have to install a Google Authenticator compatible app, those are some of the currently available:
- Authy for iOS, Android, Chrome, OS X
- FreeOTP for iOS, Android and Pebble
- Google Authenticator for iOS
- Google Authenticator for Android
- Google Authenticator (port) on Windows Store
- Microsoft Authenticator for Windows Phone
- LastPass Authenticator for iOS, Android, OS X, Windows
- 1Password for iOS, Android, OS X, Windows
Deprecation Warning
Google API for QR generator is turned off. All versions of that package prior to 5.0.0 are deprecated. Please upgrade and check documentation regarding QRCode generation.
Testing
The package tests were written with PHPUnit. There are some Composer scripts to help you run tests and analysis:
PHPUnit:
composer test
PHPStan analysis:
composer analyse
Authors
License
Google2FA is licensed under the MIT License - see the LICENSE file for details.
Contributing
Pull requests and issues are more than welcome.
Sponsorships
Direct
None.
Indirect
- JetBrains - Open Source License (since 2020)
- Blackfire - Open Source License (since 2022)