Code your dreams into reality.
Every line of code is a step towards a better future.
Embrace the bugs, they make you a better debugger.

Laravel 11 Login with Mobile Number OTP Tutorial

Last Updated on June 27, 2024 by

Providing OTP login functionality to users in laravel 11 application makes authentication easy for the user.

Here are some steps to create an authentication system using Bootstrap Authentication UI to generate, send, and verify OTP for user login:

Step 1: Set Up Bootstrap UI Auth

Run the following make ui command on cmd to install bootstrap ui auth:

cd your-laravel-application

composer require laravel/ui
php artisan ui bootstrap
php artisan ui:auth

npm install && npm run dev

Step 2: Configure SMS Provider

Edit .env file and configure your sms service provider:

TWILIO_SID=your_twilio_sid
TWILIO_AUTH_TOKEN=your_twilio_auth_token
TWILIO_FROM=your_twilio_phone_number

Step 3: Create OTP Model and Migration

Run the following command to create otp model and migration class:

php artisan make:model Otp -m

Add some fields in the database/migrations/create_otps_table migration file:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateOtpsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('otps', function (Blueprint $table) {
            $table->id();
            $table->string('mobile');
            $table->string('otp');
            $table->timestamp('expires_at');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('otps');
    }
}

Edit the User.php model and add the mobile field:

protected $fillable = [
    'name', 'email', 'password', 'mobile',
];

Run migration to create tables in database:

php artisan migrate

Step 4: Create OTPController

Create an OTP controller class that handles the OTP generator, send and verify operations in it:

php artisan make:controller OTPController

Add methods for sending and verifying OTP in OTPController:

namespace App\Http\Controllers;

use App\Models\Otp;
use Illuminate\Http\Request;
use Twilio\Rest\Client;
use Carbon\Carbon;

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 via Twilio
        $twilio = new Client(env('TWILIO_SID'), env('TWILIO_AUTH_TOKEN'));
        $twilio->messages->create($request->mobile, [
            'from' => env('TWILIO_FROM'),
            'body' => 'Your OTP is ' . $otp
        ]);

        return response()->json(['message' => 'OTP sent successfully']);
    }

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', 'Logged in successfully');
    }

    return back()->withErrors(['otp' => 'Invalid OTP or OTP expired']);
}

Step 5: Add Routes

Add routes in routes/web.php file to handle otp generator, send and verify requests:

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 a Blade view file name otp.blade.php file in resources/views/auth/ directory to send the otp:

<!DOCTYPE html>
<html>
<head>
    <title>Laravel 11 Login with OTP Example - ItcodStuff.com</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">Login with 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>

Create a Blade view file name verify.blade.php file in resources/views/auth/ directory to verify the otp:

<!DOCTYPE html>
<html>
<head>
    <title>Laravel 11 Verify OTP Example - itcodStuff.com</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: Test Application

Start the Laravel application server:

php artisan serve

Open browser and type the following url in it for testing:

http://localhost:8000/login

Leave a Comment