Laravel 11 - Login with Email OTP
Step 1: create Project
composer create-project laravel/laravel LaravelLoginWithOTP
cd LaravelLoginWithOTP
Open in any text editor like vscode, sublime text, notepad, notepad ++ etc.
Step 2 : Generate login / registration scaffolding
composer require laravel/ui
// Generate login / registration scaffolding...
php artisan ui bootstrap --auth
//Before compiling your CSS, install your project's frontend dependencies using the Node package manager (NPM):
npm install
Step 3 : configure database in .env file
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravelloginwithotp
DB_USERNAME=root
DB_PASSWORD=admin@123
Step 4 : add one column in users table using migration table (filename is 0001_01_01_000000_create_users_table.php).
Schema::create('users', function (Blueprint $table) {
.................
$table->integer('otp')->nullable();
.................
});
# add "otp" in Model page i.e User.php
protected $fillable = [
......
......
'otp',
];
Step 5 : now run the migration and create database & tables.
php artisan migrate
Step 6 : Now start the service in two tabs and check the application.
//Once the dependencies have been installed using npm install, you can compile your SASS files to plain CSS using Vite. The npm run dev command will process the instructions in your vite.config.js file. Typically, your compiled CSS will be placed in the public/build/assets directory:
php run dev
# for running the server.
php artisan serve
Now open in browser and test the pages.
http://127.0.0.1:8000
Step 7 : now register with the link
http://127.0.0.1:8000/register
and test login with registered login credentials.
Step 8 : Add link to login with OTP page in login.blade.php
....................................
....................................
@if (Route::has('password.request'))
<a class="btn btn-link" href="{{ route('password.request') }}">
{{ __('Forgot Your Password?') }}
</a>
@endif
<p>
<a class="btn btn-link" href="{{ route('login.with.otp') }}">
{{ __('Login with OTP.') }}
</a>
</p>
....................................
....................................
Step 9 : Now create loginwithotp.blade.php page.
#resources\views\loginwithotp.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">{{ __('Login With OTP') }}</div>
@if(Session::has('success'))
<div class="alert alert-success">
{{ Session::get('success') }}
</div>
@endif
@if(Session::has('error'))
<div class="alert alert-danger">
{{ Session::get('error') }}
</div>
@endif
<div class="card-body">
<form method="POST" action="{{ route('login.with.otp.post') }}">
@csrf
<div class="row mb-3">
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Send OTP') }}
</button>
@if (Route::has('password.request'))
<a class="btn btn-link" href="{{ route('confirm.login.with.otp') }}">
{{ __('already have OTP?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
Step 10 : Now create controller for opt login.
php artisan make:controller OTPController
Step 11 : Now create route in web.php
Route::view('/login-with-otp', 'auth.loginwithotp')->name('login.with.otp');
Route::post('/loginwithotppost', [App\Http\Controllers\OTPController::class, 'loginwithotppost'])->name('login.with.otp.post');
Now, check the login with otp page in browser.
http://127.0.0.1:8000/loginwithotp
Step 12 : For sending email we need the gmail smtp. So, configure the app password in google myaccount.
Open,
https://myaccount.google.com/
goto,
(left menu)->Secutiry->2-Step Verification(click on)->To continue, first verify it’s you(Provide the password for login)->click on "next" -> Click on "App passwords >" -> To create a new app specific password, type a name for it below... -> Enter app name "LaravelLoginOTP" -> Click on "Create".
Now you will get "New Generated app password"
Copy the app password and keep it safe.
example app password is: kyvplexjhqavzaps
Step 13 : Configuration of smtp in .env file. (provide the MAIL_PASSWORD is app password (without space) we created before.)
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME="inchirags@gmail.com"
MAIL_PASSWORD="kyvplexjhqavzaps"
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="inchirags@gmail.com"
MAIL_FROM_NAME="${APP_NAME}"
Step 14 : Add new method in controller -> OTPController.php
#call User Model in top (below of "use Illuminate\Http\Request;").
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Mail;
public function loginwithotppost(Request $request)
{
//dd($request);
$request->validate([
'email'=>'required|email|max:50',
]);
$checkIsUser = User::where('email', $request->email)->first();
if(is_null($checkIsUser) ){
return redirect()->route('login.with.otp')->with('error','Your account is not registered with us.');
} else {
$otp = rand(123456, 999999);
$userupdate = User::where('email',$request->email)->update([
'otp' => $otp,
]);
Mail::send('emails.loginWithOTPEmail',['otp'=>$otp],function($message) use($request){
$message->to($request->email);
$message->subject('Login with OTP - Chirags.in');
});
return redirect('confirm-login-with-otp')->withSuccess('Reset password link sent to your email address. Please check your Inbox/Spam Folder for reset password link.');
}
}
Step 15 : For email create a folder inside the
# resources->views->emails->loginWithOTPEmail.blade.php
<h1>Login with OTP eMail</h1>
<p>Your OTP is : {{ $otp }}</p>
<p>Open the bellow link:</p>
<a href="{{ route('confirm.login.with.otp') }}">Click here for confirm login with otp page.</a>
You can take any good email template.
Step 16 : Now create two more route for confirm login and confirm login post.
Route::view('/confirm-login-with-otp', 'auth.confirmloginwithotp')->name('confirm.login.with.otp');
Route::post('/confirmloginwithotppost', [App\Http\Controllers\OTPController::class, 'confirmloginwithotppost'])->name('confirm.login.with.otp.post');
Step 17 : Create method for confirmloginwithotppost inside the OTPController.php controller.
public function confirmloginwithotppost(Request $request)
{
//dd($request->all());
$request->validate([
'email' => 'required|email',
'otp' => 'required',
]);
$checkUser = User::where('otp',$request->otp)->where('email', $request->email)->first();
if(is_null($checkUser) ){
return redirect()->route('confirm.login.with.otp')->with('error','OTP or Email is incorrect.');
} else {
$user = User::where('email',$request->email)->first();
if($user){
$userupdate = User::where('email',$request->email)->update([
'otp' =>NULL
]);
Auth::login($user);
return redirect()->route('home')->with('success','Welcome to user dashboard.');
}
return redirect()->back()->with('error','Login with otp failed.');
}
}
Step 18 : create confirmloginwithotp.blade.php page inside the "resource->views->auth" folder.
@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">{{ __('Confirm Login With OTP') }}</div>
@if(Session::has('success'))
<div class="alert alert-success">
{{ Session::get('success') }}
</div>
@endif
@if(Session::has('error'))
<div class="alert alert-danger">
{{ Session::get('error') }}
</div>
@endif
<div class="card-body">
<form method="POST" action="{{ route('confirm.login.with.otp.post') }}">
@csrf
<div class="row mb-3">
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="otp" class="col-md-4 col-form-label text-md-end">{{ __('OTP') }}</label>
<div class="col-md-6">
<input id="otp" type="password" class="form-control @error('otp') is-invalid @enderror" name="otp" value="{{ old('otp') }}" required>
@error('otp')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Login') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
Step 19 : Now open in browser and test the pages.
A. Register yourself with valid email address.
http://127.0.0.1:8000/register
B. go to Login with OTP page.
http://127.0.0.1:8000/login-with-otp
After putting the email address the submit the page. You will get an email with OTP.
C. now goto
http://127.0.0.1:8000/confirm-login-with-otp
It will ask you the email and OTP. Provide the registered email address and OTP then click on submit. You'll be logged in now.
Thankyou :)