01
DecMichael Dzjaparidze introduced a two-factor authentication package for Laravel. This package currently only works out of the box with the MessageBird Verify API or the ‘null’ driver that goes through all the steps of the two-factor authentication process without actually doing any real verification. This could be useful for testing purposes. You can, however, specify a custom provider yourself. This package uses throttling to limit the number of unsuccessful authentication attempts in a certain amount of time.
To install using Composer run:
composer require michaeldzjap/twofactor-auth
If you want to use MessageBird Verify as the two-factor authentication provider then you also need to install the MessageBird PHP API:
composer require messagebird/php-rest-api
and don’t forget to add your MESSAGEBIRD_ACCESS_KEY
and TWO_FACTOR_AUTH_DRIVER=messagebird
variables to the .env
. If you instead wish to use the null
driver (default) then do NOT define the TWO_FACTOR_AUTH_DRIVER
variable in your .env
.
From Laravel 7 and onwards you will also need to install the laravel/ui package:
composer require laravel/ui
Add the service provider to the providers
array in config/app.php
:
MichaelDzjap\TwoFactorAuth\TwoFactorAuthServiceProvider::class
Run the following artisan
command to publish the configuration, language, and view files:
php artisan vendor:publish
Run the following artisan command to run the database migrations
php artisan migrate
This will add a mobile column to the users table and create a two_factor_auths
table.
Add the following trait
to your User model:
use MichaelDzjap\TwoFactorAuth\TwoFactorAuthenticable;
class User extends Authenticatable
{
use Notifiable, TwoFactorAuthenticable;
Optionally, you might want to add ‘mobile’ to your $fillable array.
The following two-factor authentication routes will be added automatically:
$router->group([
'middleware' => ['web', 'guest'],
'namespace' => 'App\Http\Controllers\Auth',
], function () use ($router) {
$router->get('/auth/token', 'TwoFactorAuthController@showTwoFactorForm')->name('auth.token');
$router->post('/auth/token', 'TwoFactorAuthController@verifyToken');
});
The first route is the route the user will be redirected to once the two-factor authentication process has been initiated. The second route is used to verify the two-factor authentication token that is to be entered by the user. The showTwoFactorForm
controller method does exactly what it says. There do exist cases where you might want to respond differently, however. For instance, instead of loading a view, you might just want to return a json response. In that case, you can simply overwrite showTwoFactorForm
in the TwoFactorAuthController
to be discussed below.
Add the following import to LoginController:
use MichaelDzjap\TwoFactorAuth\Contracts\TwoFactorProvider;
class LoginController extends Controller
{
and also add the following functions:
/**
* The user has been authenticated.
*
* @param \Illuminate\Http\Request $request
* @param mixed $user
* @return mixed
*/
protected function authenticated(Request $request, $user)
{
if (resolve(TwoFactorProvider::class)->enabled($user)) {
return self::startTwoFactorAuthProcess($request, $user);
}
return redirect()->intended($this->redirectPath());
}
and
/**
* Log out the user and start the two-factor authentication state.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\User $user
* @return \Illuminate\Http\Response
*/
private function startTwoFactorAuthProcess(Request $request, $user)
{
// Logout user, but remember user id
auth()->logout();
$request->session()->put(
'two-factor:auth', array_merge(['id' => $user->id], $request->only('email', 'remember'))
);
self::registerUserAndSendToken($user);
return redirect()->route('auth.token');
}
and lastly
/**
* Provider-specific two-factor authentication logic. In the case of MessageBird
* we just want to send an authentication token via SMS.
*
* @param \App\Models\User $user
* @return mixed
*/
private function registerUserAndSendToken(User $user)
{
// Custom, provider dependend logic for sending an authentication token
// to the user. In the case of MessageBird Verify this could simply be
// resolve(TwoFactorProvider::class)->sendSMSToken($this->user)
// Here we assume this function is called from a queue'd job
dispatch(new SendSMSToken($user));
}
You can discard the third function if you do not want to send a two-factor authentication token automatically after a successful login attempt. Instead, you might want the user to instantiate this process from the form of him/herself. In that case, you would have to add the required route and controller
method to trigger this function yourself. The best place for this would be the TwoFactorAuthController
to be discussed next.
Add a TwoFactorAuthController
in app/Http/Controllers/Auth
with the following content:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use MichaelDzjap\TwoFactorAuth\Http\Controllers\TwoFactorAuthenticatesUsers;
class TwoFactorAuthController extends Controller
{
use TwoFactorAuthenticatesUsers;
/**
* The maximum number of attempts to allow.
*
* @var int
*/
protected $maxAttempts = 5;
/**
* The number of minutes to throttle for.
*
* @var int
*/
protected $decayMinutes = 1;
/**
* Where to redirect users after two-factor authentication passes.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
}
If you want to give textual feedback to the user when two-factor authentication fails due to an expired token or when throttling kicks in you may want to add this to resources/views/auth/login.blade.php
:
<form class="form-horizontal" role="form" method="POST" action="{{ route('login') }}">
@csrf
{{-- Add this block to show an error message in case of an expired token or user lockout --}}
@if ($errors->has('token'))
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong>{{ $errors->first('token') }}</strong>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
@endif
You can Visit more details on Github.
Published at : 01-12-2021
I am a highly results-driven professional with 12+ years of collective experience in the grounds of web application development especially in laravel, native android application development in java, and desktop application development in the dot net framework. Now managing a team of expert developers at Codebrisk.
Launch project