If you want to build OTP (One-Time Password) authentication in Laravel similar to apps like:
- Google Authenticator
- Microsoft Authenticator
- Authy
Then you need to implement TOTP (Time-based One-Time Password) authentication.
This is much more secure than normal SMS OTPs because:
- Codes change every 30 seconds
- Works offline
- Uses secret keys
- Follows RFC 6238 standard
- Used in production by most modern apps
Types of OTP in Laravel
| Type | Example | Recommended |
|---|---|---|
| SMS OTP | Mobile login | ✅ |
| Email OTP | Login/Register | ✅ |
| TOTP Authenticator App | Google Authenticator | ✅✅✅ |
| WhatsApp OTP | Business apps | ✅ |
| Hardware Token OTP | Enterprise security | Advanced |
Best Package for Laravel
Use:
This package helps generate:
- Secret Keys
- QR Codes
- OTP Verification
- TOTP codes
Install Package
composer require pragmarx/google2fa
For QR Code generation:
composer require bacon/bacon-qr-code
Database Migration
Add OTP secret column to users table.
php artisan make:migration add_2fa_columns_to_users_table
Migration:
Schema::table('users', function (Blueprint $table) {
$table->text('google2fa_secret')->nullable();
$table->boolean('google2fa_enabled')->default(false);
});
Run:
php artisan migrate
Generate Secret Key
Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use PragmaRX\Google2FA\Google2FA;
use Illuminate\Support\Facades\Auth;
class TwoFactorController extends Controller
{
public function enable2FA()
{
$google2fa = new Google2FA();
$secret = $google2fa->generateSecretKey();
$user = Auth::user();
$user->google2fa_secret = $secret;
$user->save();
$QR_Image = $google2fa->getQRCodeInline(
'MyLaravelApp',
$user->email,
$secret
);
return view('2fa.enable', [
'QR_Image' => $QR_Image,
'secret' => $secret
]);
}
}
Blade View
<h2>Scan QR Code</h2>
<div>
{!! $QR_Image !!}
</div>
<p>Secret Key: {{ $secret }}</p>
How It Works
User:
- Opens Google Authenticator
- Scans QR code
- App stores secret key
- Generates 6-digit OTP every 30 seconds
Verify OTP
Controller Method:
public function verify2FA(Request $request)
{
$request->validate([
'otp' => 'required'
]);
$google2fa = new Google2FA();
$user = Auth::user();
$valid = $google2fa->verifyKey(
$user->google2fa_secret,
$request->otp
);
if ($valid) {
$user->google2fa_enabled = true;
$user->save();
return response()->json([
'success' => true,
'message' => 'OTP Verified'
]);
}
return response()->json([
'success' => false,
'message' => 'Invalid OTP'
], 422);
}
Verification Form
<form method="POST" action="/verify-2fa">
@csrf
<input type="text" name="otp" placeholder="Enter OTP">
<button type="submit">
Verify
</button>
</form>
Login Flow
Typical production flow:
User Login
↓
Email + Password Verified
↓
Check if 2FA enabled
↓
Ask OTP
↓
Verify OTP
↓
Login Success
Production Security Tips
Encrypt Secret Keys
Very important.
Use Laravel encryption:
$user->google2fa_secret = encrypt($secret);
Read:
$secret = decrypt($user->google2fa_secret);
Add Rate Limiting
Prevent brute-force attacks.
Route::post('/verify-2fa')
->middleware('throttle:5,1');
Recovery Codes
Generate backup recovery codes.
Example:
Str::random(10);
Store hashed recovery codes.
Session-based Verification
After successful OTP:
session([
'2fa_verified' => true
]);
API Authentication Example
For Laravel APIs:
POST /api/login
Response:
{
"requires_2fa": true,
"temp_token": "xxxx"
}
Then:
POST /api/verify-otp
After verification:
{
"access_token": "jwt-token"
}
Recommended Laravel Stack
| Feature | Recommended |
|---|---|
| Auth | Laravel Sanctum |
| OTP | Google2FA |
| QR Code | BaconQrCode |
| Queue | Redis |
| SMS OTP | Twilio |
| WhatsApp OTP | WATI |
| Email OTP | Laravel Notifications |
Difference Between SMS OTP & Authenticator OTP
| Feature | SMS OTP | Authenticator OTP |
|---|---|---|
| Internet Required | Yes | No |
| SIM Swap Risk | High | Low |
| More Secure | ❌ | ✅ |
| Cost | SMS charges | Free |
| Enterprise Grade | Medium | High |
Advanced Features
You can also implement:
- Device remembering
- Trusted devices
- OTP expiry handling
- Multi-device authentication
- Backup recovery codes
- WebAuthn / Passkeys
- Biometric login
Full Laravel Routes
Route::middleware('auth')->group(function () {
Route::get('/enable-2fa', [TwoFactorController::class, 'enable2FA']);
Route::post('/verify-2fa', [TwoFactorController::class, 'verify2FA']);
});
Recommended Folder Structure
app/
├── Http/
│ ├── Controllers/
│ │ └── TwoFactorController.php
│
├── Services/
│ └── OTPService.php
│
├── Actions/
│ └── VerifyOTPAction.php
Real-World Apps Using TOTP
- Google Authenticator
- Microsoft Authenticator
- LastPass Authenticator
- Duo Mobile
- Authy
Final Recommendation
For modern Laravel applications:
✅ Use Password + TOTP
✅ Store encrypted secrets
✅ Add recovery codes
✅ Use throttling
✅ Use Sanctum/JWT for APIs
✅ Use queues for SMS/email OTPs
Avoid relying only on SMS OTP for sensitive applications.





