Implementing OTP-based login functionality in a Laravel 11 application simplifies user authentication by adding an extra layer of security. Here’s how you can set up an OTP system using Bootstrap for the user interface, including generating, sending, and validating OTPs:
Step 1: Install Bootstrap UI for Authentication
Begin by setting up Bootstrap UI authentication in your Laravel project. Run these commands to install Bootstrap and configure authentication:
cd your-laravel-project
composer require laravel/ui
php artisan ui bootstrap
php artisan ui:auth
npm install && npm run dev
Step 2: Configure SMS Provider
Update your .env
file to include your SMS service provider credentials:
TWILIO_SID=your_twilio_sid
TWILIO_AUTH_TOKEN=your_twilio_auth_token
TWILIO_FROM=your_twilio_phone_number
Step 3: Create the OTP Model and Migration
Generate the OTP model and migration file by running:
php artisan make:model Otp -m
Then, modify the migration file located at database/migrations/create_otps_table.php
to include the necessary fields:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateOtpsTable extends Migration
{
public function up()
{
Schema::create('otps', function (Blueprint $table) {
$table->id();
$table->string('mobile');
$table->string('otp');
$table->timestamp('expires_at');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('otps');
}
}
Update the User.php
model to include the mobile
field:
protected $fillable = [
'name', 'email', 'password', 'mobile',
];
Run the migration to apply these changes to the database:
php artisan migrate
Step 4: Create OTP Controller
Create a controller to manage OTP generation, sending, and verification:
php artisan make:controller OTPController
In app/Http/Controllers/OTPController.php
, implement the following methods:
namespace App\Http\Controllers;
use App\Models\Otp;
use Illuminate\Http\Request;
use Twilio\Rest\Client;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
class OTPController extends Controller
{
public function sendOtp(Request $request)
{
$request->validate([
'mobile' => 'required|digits:10'
]);
$otp = rand(100000, 999999);
$expiresAt = Carbon::now()->addMinutes(5);
Otp::updateOrCreate(
['mobile' => $request->mobile],
['otp' => $otp, 'expires_at' => $expiresAt]
);
// Send OTP using Twilio
$twilio = new Client(env('TWILIO_SID'), env('TWILIO_AUTH_TOKEN'));
$twilio->messages->create($request->mobile, [
'from' => env('TWILIO_FROM'),
'body' => 'Your OTP code is ' . $otp
]);
return response()->json(['message' => 'OTP has been sent']);
}
public function verifyOtp(Request $request)
{
$request->validate([
'mobile' => 'required|digits:10',
'otp' => 'required|digits:6'
]);
$otpRecord = Otp::where('mobile', $request->mobile)->where('otp', $request->otp)->first();
if ($otpRecord && Carbon::now()->lessThanOrEqualTo($otpRecord->expires_at)) {
$user = User::firstOrCreate(['mobile' => $request->mobile]);
Auth::login($user);
return redirect()->route('home')->with('message', 'Successfully logged in');
}
return back()->withErrors(['otp' => 'Invalid or expired OTP']);
}
}
Step 5: Define Routes
Add routes for OTP operations in routes/web.php
:
use App\Http\Controllers\OTPController;
Route::post('/send-otp', [OTPController::class, 'sendOtp'])->name('send.otp');
Route::post('/verify-otp', [OTPController::class, 'verifyOtp'])->name('verify.otp');
Step 6: Create OTP Views
Create two Blade templates for OTP operations.
For sending OTP (resources/views/auth/otp.blade.php
):
<!DOCTYPE html>
<html>
<head>
<title>Login with OTP - Laravel 11</title>
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">Request OTP</div>
<div class="card-body">
<form method="POST" action="{{ route('send.otp') }}">
@csrf
<div class="form-group">
<label for="mobile">Mobile Number</label>
<input type="text" name="mobile" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Send OTP</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
For verifying OTP (resources/views/auth/verify.blade.php
):
<!DOCTYPE html>
<html>
<head>
<title>Verify OTP - Laravel 11</title>
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">Verify OTP</div>
<div class="card-body">
<form method="POST" action="{{ route('verify.otp') }}">
@csrf
<div class="form-group">
<label for="mobile">Mobile Number</label>
<input type="text" name="mobile" class="form-control" required>
</div>
<div class="form-group">
<label for="otp">OTP</label>
<input type="text" name="otp" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Verify OTP</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
Step 7: Run and Test
Launch the Laravel server with:
php artisan serve
Navigate to the following URL in your browser to test the OTP functionality:
http://localhost:8000/login