How To Two Factor Authentication Using Email In Laravel 10

Websolutionstuff | Apr-14-2023 | Categories : Laravel

In this article, we will see how to two-factor authentication using email in laravel 10. Here, we will learn about laravel 10 two-factor authentication using email. Here, we will send the OTP code to the email in laravel 10. You can two-factor verification using email in laravel 10. Also, we will use google SMTP for sending emails.

So, let's see laravel 10 two-factor authentications using email, laravel 10 two-factor authentication with email, email OTP verification in laravel 10, how to send verification code to email in laravel 10, and how to send OTP email using laravel 10.

Step 1: Install Laravel 10

In this step, we will install the laravel 10 application using the following command.

composer create-project laravel/laravel laravel_10_two_factor_auth_example

Also, we will configure the .env file.

MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
[email protected]
MAIL_PASSWORD=your_password
MAIL_ENCRYPTION=tls
[email protected]
MAIL_FROM_NAME="${APP_NAME}"

 

 

Step 2: Create Migration

In this step, we will create a migration using the following command.

php artisan make:migration create_user_email_codes

Migrations:

<?php
  
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
  
class CreateUserEmailCodes extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('user_email_codes', function (Blueprint $table) {
            $table->id();
            $table->integer('user_id');
            $table->string('code');
            $table->timestamps();
        });
    }
  
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('user_email_codes');
    }
}

After that, we will migrate the table into the database using the following command.

php artisan migrate

 

Step 3: Create Model

Now, we will update the User model and create a new UserEmailCode model.

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 Mail;
use App\Mail\SendEmailCode;
use App\Models\UserEmailCode;
  
class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
  
    /**
     * The attributes that are mass assignable.
     *
     * @var string[]
     */
    protected $fillable = [
        'name',
        'email',
        'password'
    ];
  
    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];
  
    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function generateCode()
    {
        $code = rand(1000, 9999);
  
        UserEmailCode::updateOrCreate(
            [ 'user_id' => auth()->user()->id ],
            [ 'code' => $code ]
        );
    
        try {
  
            $details = [
                'title' => 'Mail Sent from Websolutionstuff',
                'code' => $code
            ];
             
            Mail::to(auth()->user()->email)->send(new SendEmailCode($details));
    
        } catch (Exception $e) {
            info("Error: ". $e->getMessage());
        }
    }
}

app/Models/UserEmailCode.php

<?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
  
class UserEmailCode extends Model
{
    use HasFactory;
  
    public $table = "user_email_codes";
  
    protected $fillable = [
        'user_id',
        'code',
    ];
}

 

 

Step 4: Create Auth using Laravel Command

Then we will create a laravel auth scaffold using the laravel composer command.

composer require laravel/ui

After that, we will install bootstrap auth using the following command.

php artisan ui bootstrap --auth

 

Step 5: Create Middleware

Now, we will create middleware for verifying. So, run the following command and create middleware.

php artisan make:middleware Check2FA

app/Http/Middleware/Check2FA.php

<?php
  
namespace App\Http\Middleware;
  
use Closure;
use Illuminate\Http\Request;
use Session;
  
class Check2FA
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        if (!Session::has('user_2fa')) {
            return redirect()->route('2fa.index');
        }
  
        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,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        '2fa' => \App\Http\Middleware\Check2FA::class,
    ];
}
 
Step 6: Create Route

Now, we will add routes in the web.php file. So, add the following code to that file.

routes/web.php

<?php
  
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\TwoFAController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
  
Route::get('/', function () {
    return view('welcome');
});
  
Auth::routes();
  
Route::get('/home', [HomeController::class, 'index'])->name('home')->middleware('2fa');
  
Route::controller(TwoFAController::class)->group(function(){
    Route::get('two-factor-authentication', 'index')->name('2fa.index');
    Route::post('two-factor-authentication/store', 'store')->name('2fa.store');
    Route::get('two-factor-authentication/resend', 'resend')->name('2fa.resend');
});

 

 

Step 7: Create Controller

Then we will update LoginController and create a new TwoFAController using the following command.

php artisan make:controller TwoFAController

app/Http/Controllers/Auth/LoginController.php

<?php
   
namespace App\Http\Controllers\Auth;
  
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Auth;
use App\Models\UserEmailCode;
  
class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */
  
    use AuthenticatesUsers;
  
    /** 
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;
  
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function login(Request $request)
    {
        $request->validate([
            'email' => 'required',
            'password' => 'required',
        ]);
     
        $credentials = $request->only('email', 'password');
        if (Auth::attempt($credentials)) {
  
            auth()->user()->generateCode();
  
            return redirect()->route('2fa.index');
        }
    
        return redirect("login")->withSuccess('Oppes! You have entered invalid credentials);
    }
}

app/Http/Controllers/TwoFAController.php

<?php
  
namespace App\Http\Controllers;
  
use Illuminate\Http\Request;
use Session;
use App\Models\UserEmailCode;
  
class TwoFAController extends Controller
{
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function index()
    {
        return view('2fa');
    }
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function store(Request $request)
    {
        $request->validate([
            'code'=>'required',
        ]);
  
        $find = UserEmailCode::where('user_id', auth()->user()->id)
                        ->where('code', $request->code)
                        ->where('updated_at', '>=', now()->subMinutes(1))
                        ->first();
  
        if (!is_null($find)) {
            Session::put('user_2fa', auth()->user()->id);
            return redirect()->route('home');
        }
  
        return back()->with('error', 'You entered wrong code.');
    }
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function resend()
    {
        auth()->user()->generateCode();
  
        return back()->with('success', 'We re-sent code to on your email.');
    }
}
 
Step 8: Create Mail Class

Now, we will create a mail class for sending mail to users. So, run the following command and create a mailable class.

php artisan make:mail SendEmailCode

app/Mail/SendEmailCode.php

<?php
  
namespace App\Mail;
  
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
  
class SendEmailCode extends Mailable
{
    use Queueable, SerializesModels;
 
    public $details;
    
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($details)
    {
        $this->details = $details;
    }
    
    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->subject('Mail from Websolutionstuff')
                    ->view('emails.code');
    }
}
 
Step 9: Create Blade File

Now, we will create a 2fa.blade.php file. So, add the following HTML code to that file.

resources/views/2fa.blade.php

@extends('layouts.app')
  
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Laravel 9 Two Factor Authentication Using Email - Websolutionstuff</div>
  
                <div class="card-body">
                    <form method="POST" action="{{ route('2fa.store') }}">
                        @csrf
  
                        <p class="text-center">We sent code to email : {{ substr(auth()->user()->email, 0, 5) . '******' . substr(auth()->user()->email,  -2) }}</p>
  
                        @if ($message = Session::get('success'))
                            <div class="row">
                              <div class="col-md-12">
                                  <div class="alert alert-success alert-block">
                                    <button type="button" class="close" data-dismiss="alert">×</button> 
                                      <strong>{{ $message }}</strong>
                                  </div>
                              </div>
                            </div>
                        @endif
  
                        @if ($message = Session::get('error'))
                            <div class="row">
                              <div class="col-md-12">
                                  <div class="alert alert-danger alert-block">
                                    <button type="button" class="close" data-dismiss="alert">×</button> 
                                      <strong>{{ $message }}</strong>
                                  </div>
                              </div>
                            </div>
                        @endif
  
                        <div class="form-group row">
                            <label for="code" class="col-md-4 col-form-label text-md-right">Code</label>
  
                            <div class="col-md-6">
                                <input id="code" type="number" class="form-control @error('code') is-invalid @enderror" name="code" value="{{ old('code') }}" required autocomplete="code" autofocus>
  
                                @error('code')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>
  
                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <a class="btn btn-link" href="{{ route('2fa.resend') }}">Resend Code?</a>
                            </div>
                        </div>
  
                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    Submit
                                </button>
  
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

resources/views/emails/code.blade.php

<!DOCTYPE html>
<html>
<head>
    <title>Websolutionstuff</title>
</head>
<body>
    <h1>{{ $details['title'] }}</h1>
    <p>Your code is: {{ $details['code'] }}</p>
     
    <p>Thank you</p>
</body>
</html>
 

 

Step 10: Run Laravel Application

Now, we will run laravel 10 two-factor authentication using email.

php artisan serve

 


You might also like:

Recommended Post
Featured Post
How To Login With OTP In Laravel 10
How To Login With OTP In Larav...

In today's digital age, where security is paramount, user authentication has become a cornerstone concern for web ap...

Read More

Aug-21-2023

How to Create Payment Link in Stripe using API in Laravel 10
How to Create Payment Link in...

In today's digital age, the ability to facilitate online payments efficiently is crucial for businesses and develope...

Read More

Oct-09-2023

Carbon Add Days To Date In Laravel 9
Carbon Add Days To Date In Lar...

In this article, we will see carbon add day and add days to date in laravel 9. Carbon provides the addDay() and add...

Read More

Nov-17-2022

How To Replace All Occurrences Of String In Javascript
How To Replace All Occurrences...

In this article, we will see how to replace all occurrences of a string in javascript. You can use the javascript r...

Read More

Nov-07-2022