google2fa-laravel: a TOTP second factor for Laravel applications
A One Time Password Authentication package, compatible with Google Authenticator for Laravel
At a glance
- What is it?
- This package wires the pragmarx/google2fa core implementation into Laravel, generating QR codes for Google Authenticator and checking the codes users type. It ships a middleware, a facade and a configurable view, and it leaves recovery codes to a separate package.
- Who is it for?
- Adopt google2fa-laravel when your Laravel application needs a TOTP second factor compatible with Google Authenticator and you want the verification step expressed as a middleware rather than hand-rolled code in each controller. Do not adopt it expecting recovery codes, since the README routes that to a separate package, and check the version 3.x compatibility table against your Laravel and PHP versions before you start.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 97 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the package does, and what it deliberately leaves out
The problem is familiar: a Laravel application that wants a second authentication factor, where users confirm their identity with a rotating six digit code from an authenticator app on their phone.
The mechanism underneath is standard. The README describes Google2FA as a PHP implementation of the Google Two-Factor Authentication Module, supporting the HMAC-Based One-time Password algorithm specified in RFC 4226 and the Time-based One-time Password algorithm specified in RFC 6238. Those two RFCs are the whole story of the crypto: a shared secret, a counter or a time step, and a truncated hash that becomes a code the user reads.
What this repository adds is the Laravel side. It is described as a bridge to the Google2FA PHP package, and the stated intent is to create QR codes and check the codes the user typed. Everything else follows from that framing, including what is missing: backup and recovery codes are not part of this package, and the README points to a separate Recovery Package for that job.
That split is worth dwelling on, because recovery codes are the part of a two factor rollout that teams tend to defer. A user who loses their phone has no way back in unless the application provides an alternative, and this package hands you the verification half of the problem while leaving the recovery half to another dependency you have to evaluate separately.
Facade, container binding, and the same call behind both
The package exposes two ways to reach the underlying service, and the documentation is explicit that they are equivalent. The first is the facade, imported under the name Google2FA:
use Google2FA;
return Google2FA::generateSecretKey();The second is the IoC container, using the container binding name directly:
$google2fa = app('pragmarx.google2fa');
return $google2fa->generateSecretKey();Both call generateSecretKey(), which is the entry point for the whole flow. The secret it produces is what the authenticator app scans, and it is the value you must store against the user. The README does not document where that secret should live, how it should be encrypted at rest, or what happens to it when a user re-enrols, so those decisions are yours.
On Laravel 5.5 and above there is nothing else to wire up. The README says the package autoloads the Service Provider and creates the Alias using the Auto-Discovery feature. Below that, the Service Provider and the facade alias have to be added by hand to config/app.php:
PragmaRX\Google2FALaravel\ServiceProvider::class,
'Google2FA' => PragmaRX\Google2FALaravel\Facade::class,The alias name there, Google2FA, is the one used in the use statement at the top of the facade example, which is why the facade import reads the way it does.
Installing the package and publishing its config
Installation is a Composer operation. For the current line, which the README marks as requiring PHP 7.0 and above:
composer require pragmarx/google2fa-laravelA legacy 2.x install, needed only if you still require PHP 5 support, is pinned explicitly:
composer require pragmarx/google2fa-laravel:^2.0The package then needs its configuration file published so you can change the view name, the input name and the QR code backend. That is a standard Artisan vendor publish call:
php artisan vendor:publish --provider="PragmaRX\Google2FALaravel\ServiceProvider"After that, the published file is config/google2fa.php. The README is explicit about where these settings live, which is a small but real convenience: the one time password view is a config key, not a hardcoded route.
One practical note on the package name. The repository is antonioribeiro/google2fa-laravel, but the Composer package you install is pragmarx/google2fa-laravel, and the badges in the README point at the pragmarx Packagist page. The vendor prefix and the repository owner differ, so search for the pragmarx name when you look for the package, the documentation or the playground.
The 2fa middleware, and where it attaches to your routes
Rather than making you check a code inside a controller, the package provides a middleware. You register it under a short alias in the route middleware array of your Kernel.php:
protected $routeMiddleware = [
...
'2fa' => \PragmaRX\Google2FALaravel\Middleware::class,
];From there the alias is used like any other middleware, which is what makes this package pleasant to use. A route that requires a second factor declares it:
Route::get('/admin', function () {
return view('admin.index');
})->middleware(['auth', '2fa']);The alias name, 2fa, is yours to choose, so naming it something else costs nothing. What the README does not spell out is the middleware's own decision logic: how it decides a user needs a prompt rather than a pass, what it does when the user has no secret yet, and whether it works only for session-based authentication. The README links to a middleware demo page and a separate example application, so the intended usage is best learned from those rather than from a configuration reference.
The one input contract the README does document is the view and its form field. The view key in config/google2fa.php names the screen shown to the user:
/**
* One Time Password View
*/
'view' => 'google2fa.index',and the name of the input inside that view is configurable too:
/**
* One Time Password request input name
*/
'otp_input' => 'one_time_password',which matches the form in the documentation:
<form action="/google2fa/authenticate" method="POST">
<input name="one_time_password" type="text">
<button type="submit">Authenticate</button>
</form>The action path is the piece to check against your own routes, because that is where the middleware expects the code to be posted.
Three QR code backends, chosen in config or at runtime
Enrolment starts with a QR code the user scans with Google Authenticator. The README says the QR code work is handled by the Google2FA-QRCode package, and that you should consult that project for how to configure the generators properly. The division keeps this repository focused on the Laravel wiring, but it also means the QR configuration lives in a dependency's documentation.
There are three backends: imagemagick, which is the default, plus svg and eps. The choice is a config key in the published file:
/*
* Which image backend to use for generating QR codes?
*
* Supports imagemagick, svg and eps
*/
'qrcode_image_backend' => \PragmaRX\Google2FALaravel\Support\Constants::QRCODE_IMAGE_BACKEND_IMAGEMAGICK,It can also be changed at runtime, which is useful when a deployment lacks ImageMagick and you want to fall back to vector output:
Google2FA::setQRCodeBackend('svg');The default choice of ImageMagick is the one to think about. It means an ImageMagick installation on the server that renders the enrolment screen, and a deployment target where that binary exists and is permitted to run. The svg backend removes that external dependency, at the cost of a different rendering path that the README does not describe in detail. What the README does not cover is what a user sees if the QR code cannot be generated at all, and there is no documented manual entry fallback for the secret, so an ImageMagick failure at enrolment time is a real failure mode rather than a degraded one.
OTP lifetime is capped by the session, and that is the trap
The package lets you re-ask for a one time password periodically instead of accepting it for the rest of the session. The setting is a number of minutes, with zero meaning the code is never re-requested:
/**
* Lifetime in minutes.
* In case you need your users to be asked for a new one time passwords from time to time.
*/
'lifetime' => 0, // 0 = eternalThe documentation is unusually clear about the interaction, and the interaction is the thing to get right. The README states that this uses the Laravel sessions in the background, and that if this number exceeds the value set in config('session.lifetime') you will still be logged out even if your OTP lifetime has not expired.
In other words, the OTP lifetime is bounded above by the session lifetime. Setting a thirty minute OTP lifetime inside a fifteen minute session configuration gives you a prompt every session rather than every thirty minutes, and the behaviour will look like a bug until you notice the config relationship.
The other half of the same mechanism is that the code is remembered for the session. The README describes the usual case as an OTP lasting forever, until the user logs off the application. That is a deliberate design choice, and it carries an implication for risk: a stolen session cookie is not challenged by a second factor, because the factor was already satisfied earlier in the same session. Sessions therefore become the security boundary in that configuration, and the session lifetime and cookie settings deserve as much attention as the OTP settings themselves.
Version 3.x coverage, the legacy 2.x line, and the licence
The compatibility tables are the most useful part of the documentation, because a two factor package that does not install on your framework version is useless to you. Version 3.x covers a wide range, from Laravel 5.4.36 on PHP 7.0 to 7.3, through 6.x, 7.x, 8.x, 9.x, 10.x, 11.x and 12.x, up to 13.x on PHP 8.3 to 8.5. The 2.x line is marked legacy and exists for PHP 5 support, covering Laravel 5.2 through 7.x.
The historical table records why the package is split into two repositories. Before Google2FA 2.0, at Laravel 5.1, the same package was both a Laravel package and a PHP agnostic one, so older installs needed pragmarx/google2fa:~1.0. From Google2FA 2.0 onwards, with Laravel 5.2 and above, the core and the bridge were separated, and the table records the pairing of core and bridge versions.
The licence is MIT, with a LICENSE file at the root of the repository, and the README badge points at it. The repository also carries a CHANGELOG.md and an upgrading.md, which is worth reading before you bump versions, since an authentication package's changes tend to affect the login flow.
On maintenance, the repository is not archived and the last push was on 2026-07-18. The most recent published release tags in the list are v1.3.3 from 2020-04-05 and v1.3.2 from 2020-04-02, so the release tags lag the branch work by a long way. The current state of the code is on the 3.x branch, which is the default branch, and the compatibility tables in the README are the authoritative statement of what that branch supports.
Editorial conclusion
Adopt google2fa-laravel when your Laravel application needs a TOTP second factor compatible with Google Authenticator and you want the verification step expressed as a middleware rather than hand-rolled code in each controller. Do not adopt it expecting recovery codes, since the README routes that to a separate package, and check the version 3.x compatibility table against your Laravel and PHP versions before you start. Verify first that the secret generated by generateSecretKey() is stored per user, that your session lifetime is longer than the OTP lifetime you configure, and that the composer require command for the 3.x line resolves against your application.
Frequently asked questions
How do I install google2fa-laravel in a Laravel application?
The README gives a Composer command, `composer require pragmarx/google2fa-laravel` for the current 3.x line, and a pinned `composer require pragmarx/google2fa-laravel:^2.0` for the legacy line that supports PHP 5. On Laravel 5.5 and above the service provider and alias autoload, and the config file is published with `php artisan vendor:publish`.
Does google2fa-laravel include backup and recovery codes?
No. The README states that this package creates QR codes and checks the codes users type, and directs you to a separate Recovery Package if you need backup or recovery codes to let users regain access to a lost account.
Which Laravel and PHP versions does the 3.x branch support?
The compatibility table for version 3.x runs from Laravel 5.4.36 on PHP 7.0 to 7.3, through Laravel 6.x to 12.x, up to Laravel 13.x on PHP 8.3 to 8.5. Version 2.x is marked legacy and exists for PHP 5 support.
How long does a one time password stay valid in google2fa-laravel?
The config option `lifetime` sets a number of minutes, with 0 meaning eternal, and the README notes that it uses Laravel sessions in the background. If that value exceeds config('session.lifetime') the user is still logged out when the session ends.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/antonioribeiro-google2fa-laravel)Was this useful?