Loading repository data…
Loading repository data…
Laragear / repository
Two-Factor Authentication for all your users out-of-the-box.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
On-premises Two-Factor Authentication for all your users out of the box.
use Illuminate\Http\Request;
use Laragear\TwoFactor\Facades\Auth2FA;
public function login(Request $request)
{
$attempt = Auth2FA::attempt($request->only('email', 'password'));
if ($attempt) {
return 'You are logged in!';
}
return 'Hey, you should make an account!';
}
This package enables TOTP authentication using 6 digits codes. No need for external APIs.
[!TIP]
Want to authenticate users with Passkeys? Check out Laragear WebAuthn.
Your support allows me to keep this package free, up-to-date and maintainable. Alternatively, you can spread the word on social media!
Fire up Composer and require this package in your project.
composer require laragear/two-factor
That's it.
This package adds a Contract to detect if a user, after the credentials are deemed valid, should use Two-Factor Authentication as a second layer of authentication.
It includes a custom view and a helper to handle the Two-Factor authentication itself during login attempts.
Works without middleware or new guards, but you can go full manual if you want.
two-factor:install Artisan command.php artisan two-factor:install
[!TIP]
You can edit the migration by adding new columns before migrating, and also change the table name.
After that, you may migrate your table like always through the Artisan command.
php artisan migrate
TwoFactorAuthenticatable contract and the TwoFactorAuthentication trait to the User model, or any other model you want to make Two-Factor Authentication available.<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laragear\TwoFactor\TwoFactorAuthentication;
use Laragear\TwoFactor\Contracts\TwoFactorAuthenticatable;
class User extends Authenticatable implements TwoFactorAuthenticatable
{
use TwoFactorAuthentication;
// ...
}
[!TIP]
The contract is used to identify the model using Two-Factor Authentication, while the trait conveniently implements the methods required to handle it.
That's it. You're now ready to use 2FA in your application.
To enable Two-Factor Authentication for the User, he must sync the Shared Secret between its Authenticator app and the application.
[!TIP]
Free Authenticator Apps, in no particular order, are iOS Authenticator, FreeOTP, Authy, 2FAS, 2Stable Authenticator, Step-two, BinaryRoot Authenticator and Google Authenticator.
To start, generate the necessary data using the createTwoFactorAuth() method. This returns a serializable Shared Secret that you can show to the User as a string or QR Code (encoded as SVG) in your view.
use Illuminate\Http\Request;
public function prepareTwoFactor(Request $request)
{
$secret = $request->user()->createTwoFactorAuth();
return view('user.2fa', [
'qr_code' => $secret->toQr(), // As QR Code
'uri' => $secret->toUri(), // As "otpauth://" URI.
'string' => $secret->toString(), // As a string
]);
}
[!TIP]
When you use
createTwoFactorAuth()on someone with Two-Factor Authentication already enabled, the previous data becomes permanently invalid. This ensures a User never has two Shared Secrets enabled at any given time.
Then, the User must confirm the Shared Secret with a Code generated by their Authenticator app. The confirmTwoFactorAuth() method will automatically enable it if the code is valid.
use Illuminate\Http\Request;
public function confirmTwoFactor(Request $request)
{
$request->validate([
'code' => 'required|numeric'
]);
$activated = $request->user()->confirmTwoFactorAuth($request->code);
// ...
}
If the User doesn't issue the correct Code, the method will return false. You can tell the User to double-check its device's timezone, or create another Shared Secret with createTwoFactorAuth().
Recovery Codes are automatically generated each time the Two-Factor Authentication is enabled. By default, a Collection of ten one-use 8-characters codes are created.
You can show them using getRecoveryCodes().
use Illuminate\Http\Request;
public function confirmTwoFactor(Request $request)
{
if ($request->user()->confirmTwoFactorAuth($request->code)) {
return $request->user()->getRecoveryCodes();
}
return 'Try again!';
}
You're free on how to show these codes to the User, but ensure you show them at least one time after a successfully enabling Two-Factor Authentication, and ask him to print them somewhere.
[!TIP]
These Recovery Codes are handled automatically when the User sends it instead of a TOTP code. If it's a recovery code, the package will use and mark it as invalid, so it can't be used again.
The User can generate a fresh batch of codes using generateRecoveryCodes(), which replaces the previous batch.
use Illuminate\Http\Request;
public function showRecoveryCodes(Request $request)
{
return $request->user()->generateRecoveryCodes();
}
[!IMPORTANT]
If the User depletes his recovery codes without disabling Two-Factor Authentication, or Recovery Codes are deactivated, he may be locked out forever without his Authenticator app. Ensure you have countermeasures in these cases, like recovery emails.
While it's not recommended, as the included logic will suffice for the vast majority of situations, you can create your own generator for recovery codes. Just add a callback using the generateRecoveryCodesUsing() of the TwoFactorAuthentication model.
This method receives a callback that should return a random alphanumeric code, and will be invoked on each code to generate.
use Laragear\TwoFactor\Models\TwoFactorAuthentication;
use MyRandomGenerator;
$generator = function ($length, $iteration, $amount) {
return MyRandomGenerator::random($length)->make();
}
TwoFactorAuthentication::generateRecoveryCodesUsing($generator);
The easiest way to login users in your application is to use the Auth2FA facade. It comes with everything you would need to handle a user that requires a 2FA Code:
In your Login Controller, use the Auth2FA::attempt() method with the credentials. If the user requires a 2FA Code, it will automatically stop the authentication and show a form to use it.
You can blatantly copy-and-paste this code in your log in controller:
use Laragear\TwoFactor\Facades\Auth2FA;
use Illuminate\Http\Request;
public function login(Request $request)
{
// If the user is trying for the first time, ensure both email and the password are
// required to log in. If it's not, then he would issue its 2FA code. This ensures
// the credentials are not required again when is just issuing his 2FA code alone.
if ($request->isNotFilled('2fa_code')) {
$request->validate([
'email' => 'required|email',
'password' => 'required|string'
]);
}
$attempt = Auth2FA::attempt($request->only('email', 'password'), $request->filled('remember'));
if ($attempt) {
return redirect()->home();
}
return back()->withErrors(['email' => 'There is no existing user for these credentials']);
}
You can further customize how to handle the 2FA code authentication procedure with the following fluent methods:
| Method | Description |
|---|---|
guard($guard) | The guard to use for authentication. Defaults to the application default (web). |
view($view) | Return a custom view to handle the 2FA Code retry. |
redirect($route) | Redirect to a location to handle the 2FA Code retry. |
message($message) | Return a custom message when the 2FA code fails or is not present. |
input($input) | Sets the input where the TOTP code is in the request. Defaults to 2fa_code. |
sessionKey($key) | The key used to flash the encrypted credentials. Defaults to _2fa_login. |
For example, we can change the message to show and the input to use from the login form.
use Laragear\TwoFactor\Facades\Auth2FA;
Auth2FA::message('You need 2FA set up to access this area')
->redirect('/auth/2fa-required')
->input('2fa-code')
->attempt($request->only('email', 'password'), $request->filled('remember'));
[!NOTE]
If you're using scaffolding packages like Laravel UI, Breeze, Fortify, JetStream, Inertia or Livewire, to name some, you may require to change or alter their proper authentication flow. Refer to their documentation for further details.
Alternatively, you may use Auth::attemptWhen() with TwoFactor helper methods, which returns a callback to check if the user needs a 2FA Code before proceeding using TwoFactor::hasCode().
use Illuminate\Support\Facades\Auth;
use Laragear\TwoFactor\TwoFactor;
$attempt = Auth::attemptWhen(
[/* Credentials... */], TwoFactor::hasCode(), $request->filled('remember')
);
You can use the hasCodeOrFails() method that does the same, but throws a validation exception, which is handled gracefully by the framework. It even accepts a custom message in case of failure, otherwise a default translation line will be used.
When the user is under a safe device, which is determined by cookie, no 2FA code will be required to log in. To check if this was the case on the current request, use the wasTwoFactorBypassedBySafeDevice() method on the user.
use Illuminate\Http\Request;
public function changeServerSetting(Request $request)
{
if ($request->user()->wasTwoFactorBypassedBySafeDevice())