In this article, we will learn 2fa Laravel (Two Factor Authentication) with an SMS tutorial with example. We will use the composer package twilio/sdk to send SMS using the Laravel. Let’s just see how to do it.
Step 1: Install Laravel
If you already have installed Laravel on your local machine then you can skip this step. You can easily install the fresh version of Laravel by running the below command in your terminal. You can give it any name but in this case, we will name it demo-app
.
composer create-project --prefer-dist laravel/laravel demo-app
Step 2: Install twilio/sdk Package
Next, we need to install twilio/sdk composer package to use Twilio API. Change your current working directory to demo-app and run the composer command as below:
cd demo-app
composer require twilio/sdk
If you don’t have composer installed on your PC you can do so by following the instructions here.
Step 3: Create Twilio Account
First, we need to create a Twilio account. Then, go to your Twilio dashboard and grab your Account SID
and Auth Token
.
Now go to the Phone Number menu section to get your SMS-enabled phone number.
Step 4: Update .env File
The next step is to update the .env
file with your Twilio credentials. So open up .env
located at the root of the project directory and add the following values:
TWILIO_SID="INSERT YOUR TWILIO SID HERE"
TWILIO_AUTH_TOKEN="INSERT YOUR TWILIO TOKEN HERE"
TWILIO_NUMBER="+91***************"
Notes: After adding values in the .env
file you need to clear the config cache by running the below command:
php artisan config:clear
Step 5: Update User Migration
In this step, we will add otp
column in users
table.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->text('title')->nullable();
$table->text('first_name');
$table->text('middle_name')->nullable();
$table->text('last_name');
$table->string('email')->unique();
$table->string('phone')->nullable();
$table->string('password')->nullable();
$table->integer('otp')->nullable();
$table->rememberToken();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('users');
}
}
Now you have to run this migration by the following command:
php artisan migrate
Or if you are working in local then you can run the following command but make sure this command will drop all the tables first and recreate it.
php artisan migrate:fresh
Step 6: Update User Model
Now, we need to update the user
model and create a new method that will generate the 6-digit OTP code randomly and send it to the user.
app/Models/User.php
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Exception;
use Twilio\Rest\Client;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
protected $fillable = [
'title',
'first_name',
'middle_name',
'last_name',
'email',
'phone',
'password',
'otp',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function sendOtp()
{
$user = Auth::user();
$otp = mt_rand(100000,999999);
User::updateOrCreate(
[ 'id' => $user->id ],
[ 'otp' => $otp ]
);
$receiverNumber = $user->phone;
$message = "Your login code is ". $code;
try {
$accountSid = getenv("TWILIO_SID");
$authToken = getenv("TWILIO_TOKEN");
$twilioNumber = getenv("TWILIO_FROM");
$client = new Client($accountSid, $authToken);
$client->messages->create($receiverNumber, [
'from' => $twilioNumber,
'body' => $message
]);
} catch (Exception $e) {
info("Error: ". $e->getMessage());
}
}
}
Step 7: Create Auth Scaffold
Here, we will use laravel ui
package to create auth scaffold with the bootstrap framework which will generate the Login, Register, and other auth-related functionality. Run the below command:
composer require laravel/ui
Now, let’s run the command for creating auth scaffold:
php artisan ui bootstrap --auth
Step 8: Create Middleware
In this step, we will create new middleware to check whether the user has 2fa or not. So let’s create a new middleware with the following command and code:
php artisan make:middleware CheckOtp
app/Http/Middleware/CheckOtp.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
class CheckOtp
{
public function handle(Request $request, Closure $next)
{
if (!empty(auth()->user()) && !empty(auth()->user()->otp)) {
return Redirect::route('login.verify');
}
return $next($request);
}
}
app/Http/Kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
...
...
...
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'remember' => \Reinink\RememberQueryStrings::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'check.otp' => \App\Http\Middleware\CheckOtp::class,
];
}
Step 9: Create Routes
We need to add routes in routes/web.php
file to perform the 2fa Laravel send SMS. The first GET
route is used to show the verify OTP form and another route for the POST
method to verify the OTP in Laravel.
routes/web.php
<?php
use App\Http\Controllers\Auth\LoginController;
use App\Http\Controllers\DashboardController;
use Illuminate\Support\Facades\Route;
Route::get('login', [LoginController::class, 'showLoginForm'])
->name('login')
->middleware('guest');
Route::post('login', [LoginController::class, 'login'])
->name('login.attempt')
->middleware('guest');
Route::get('verify-login', [LoginController::class, 'showOtpForm'])
->name('login.verify');
Route::post('verify-login', [LoginController::class, 'verifyLogin'])
->name('verify.attempt');
//Route::get('resend-otp/{isResend}', [LoginController::class, 'sendOtp'])
//->name('resend.otp')->middleware('throttle:5,1');
Route::group(['middleware' => ['auth', 'check.otp']], function() {
// Dashboard
Route::get('/', [DashboardController::class, 'index'])
->name('dashboard');
});
Step 10: Create LoginController
Let’s create a LoginController
and let’s add two methods, one for the display SMS sending form and the second for the sending messages to the receiver. To create a controller run the below command:
php artisan make:controller LoginController
After running the above command a new file will be created in Controllers
the directory, open it, and add the following method.
app/Http/Controllers/LoginController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use App\Http\Requests\Auth\Login;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\RedirectsUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Session;
class LoginController extends Controller
{
use AuthenticatesUsers, RedirectsUsers, ThrottlesLogins;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
public function showLoginForm(Request $request)
{
return view('auth.login');
}
public function showOtpForm()
{
return view('auth.verify');
}
public function login(Login $request)
{
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
$user = Auth::user();
$this->clearLoginAttempts($request);
$user->sendOtp();
return redirect()->route('auth.verify')->withSuccess('Login OTP has been sent to your mobile.');
} else {
$this->incrementLoginAttempts($request);
return Redirect::back()->with('error', 'Invalid credentials.');
}
}
public function verifyLogin(Request $request)
{
$request->validate([
'otp'=>'required',
]);
$user = User::where('id', auth()->user()->id)
->where('otp', $request->otp)
->first();
if (!is_null($user)) {
$request->user()->otp = null;
$request->user()->save();
return Redirect::route('dashboard')->with('success', 'Welcome '. $user->first_name);
}
return back()->with('error', 'You entered wrong code.');
}
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard();
}
}
Step 11: Create Blade/HTML File
At last, we need to create a verify.blade.php
file in the views folder, and in this file, we will add the top verify Form HTML.
resources/views/auth/verify.blade.php
<!DOCTYPE html>
<html>
<head>
<title>2FA Laravel With SMS Tutorial Examples - ScratchCode.io</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">
<div class="panel panel-primary">
<div class="panel-heading">
<h2>2FA Laravel With SMS Tutorial Examples - ScratchCode.io</h2>
</div>
<div class="panel-body">
@if ($message = Session::get('success'))
<div class="alert alert-success alert-block">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{{ $message }}</strong>
</div>
@endif
@if (count($errors) > 0)
<div class="alert alert-danger">
<strong>Whoops!</strong> There were some problems with your input.
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('verify.attempt') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="row">
<div class="col-md-12">
<div class="col-md-6 form-group">
<label>Otp:</label>
<input type="text" name="otp" class="form-control"/>
</div>
<div class="col-md-6 form-group">
<button type="submit" class="btn btn-success">Verify Otp</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
If you have SSL error then follow the following step:
1. Download the following file – cacert.pem
2. Then download the following file – thawte_Premium_Server_CA.pem
3. Open the second file in a text editor and copy its contents into the first file (cacert.pem at the bottom/end).
Save cacert.pem and add the following lines to your php.ini :
[curl]
curl.cainfo=c:/xampp/php/cacert.pem
Obviously, change the directory to the one where your pem is located. Restart the PHP local server (xampp/wamp). Then it will work flawlessly.
Step 12: Output
Hurray! We have completed all steps for the 2FA Laravel with SMS. Let’s run the below command and see how it’s working.
php artisan serve
After running the above command, open your browser and visit the site below URL:
http://localhost:8000/login
Additionally, read our guide:
- Laravel: Blade Switch Case Statement Example
- Laravel: Switch Case Statement In Controller Example
- Laravel: Change Column Type In Migration
- Laravel: Change Column Name In Migration
- How To Use Where Date Between In Laravel
- How To Add Laravel Next Prev Pagination
- Laravel Remove Column From Table In Migration
- Laravel: Get Month Name From Date
- Laravel: Increase Quantity If Product Already Exists In Cart
- How To Update Pivot Table In Laravel
- How To Install Vue In Laravel 8 Step By Step
- How To Handle Failed Jobs In Laravel
- Best Ways To Define Global Variable In Laravel
- How To Get Latest Records In Laravel
- How To Break Nested Loops In PHP Or Laravel
- How To Pass Laravel URL Parameter
- Laravel Run Specific Migration
- Redirect By JavaScript With Example
- How To Schedule Tasks In Laravel With Example
- Laravel Collection Push() And Put() With Example
That’s it from our end. We hope this article helped you to learn the 2fa Laravel with SMS tutorial with the example.
Please let us know in the comments if everything worked as expected, your issues, or any questions. If you think this article saved your time & money, please do comment, share, like & subscribe. Thank you for reading this post 🙂 Keep Smiling! Happy Coding!