mchuluq / laravel-mfa
Multi-Factor Authentication package for Laravel with TOTP, Email OTP, and WebAuthn support
Requires
- php: ^8.1
- bacon/bacon-qr-code: ^2.0
- illuminate/auth: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/contracts: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/cookie: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/database: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/encryption: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/http: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/mail: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/routing: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/session: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^8.0|^9.0|^10.0|^11.0|^12.0
- illuminate/validation: ^8.0|^9.0|^10.0|^11.0|^12.0
- nyholm/psr7: ^1.8
- paragonie/constant_time_encoding: ^2.4
- psr/http-message: ^1.0|^2.0
- ramsey/uuid: ^4.0
- spomky-labs/otphp: ^11.4.3
- web-auth/cose-lib: ^4.0
- web-auth/webauthn-lib: ^5.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- mockery/mockery: ^1.4
- orchestra/testbench: ^6.0|^9.0|^10.0
- phpstan/phpstan: ^0.12|^1.0
- phpunit/phpunit: ^9.3|^10.0|^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-24 05:14:43 UTC
README
Multi-Factor Authentication package for Laravel 8+ with support for TOTP, Email OTP, and WebAuthn/Passkey.
Features
- 🔐 Multiple MFA Methods: TOTP (Authenticator Apps), Email OTP, WebAuthn/Passkey
- 🎨 Driver Pattern: Easy to extend with custom drivers
- 🛡️ Security First: Rate limiting, backup codes, device remembering
- 🎯 Middleware Based: Simple integration as authentication layer
- 📱 User Friendly: Multiple methods per user, fallback options
- 🔧 Highly Configurable: Extensive configuration options
- 🎭 Laravel 8+ Compatible: Built specifically for Laravel 8
Requirements
- PHP ^7.4 or ^8.0
- Laravel ^8.0
- MySQL/PostgreSQL/SQLite
Installation
1. Install via Composer
composer require mchuluq/laravel-mfa
2. Publish
php artisan vendor:publish --tag=mfa-config php artisan vendor:publish --tag=mfa-migrations php artisan vendor:publish --tag=mfa-vue php artisan vendor:publish --tag=mfa-blade php artisan migrate
3. Add Trait to User Model
use Mchuluq\LaravelMFA\Traits\HasMFA; class User extends Authenticatable { use HasMFA; // ... }
Configuration
Edit config/mfa.php:
return [ 'enabled' => true, 'drivers' => [ 'totp' => [ 'enabled' => true, // ... ], 'email_otp' => [ 'enabled' => true, // ... ], 'webauthn' => [ 'enabled' => true, // ... ], ], // ... ];
Usage
Protect Routes with MFA
// routes/web.php Route::middleware(['auth', 'mfa'])->group(function () { Route::get('/dashboard', [DashboardController::class, 'index']); Route::get('/profile', [ProfileController::class, 'show']); });
Setup MFA for User
// In your controller public function enableTotp(Request $request) { $user = auth()->user(); // Setup TOTP $setup = mfa('totp')->setup($user); return view('mfa.setup.totp', [ 'qrCode' => $setup['qr_code'], 'secret' => $setup['secret'], 'backupCodes' => $setup['backup_codes'], ]); } public function verifyTotp(Request $request) { $user = auth()->user(); $code = $request->input('code'); if (mfa('totp')->verify($user, $code)) { return redirect()->route('dashboard') ->with('success', 'MFA enabled successfully!'); } return back()->withErrors(['code' => 'Invalid code']); }
Check MFA Status
// Check if user has MFA enabled if ($user->hasMFAEnabled()) { // ... } // Get enabled methods $methods = $user->getMFAMethods(); // Get primary method $primary = $user->getPrimaryMFAMethod();
Using Helper Functions
// Get MFA manager $manager = mfa(); // Get specific driver $totp = mfa('totp'); // Check if MFA is verified in session if (mfa_verified()) { // User has verified MFA } // Check if user requires MFA if (mfa_required()) { // Redirect to challenge }
Available Drivers
1. TOTP (Time-based One-Time Password)
Works with authenticator apps like:
- Google Authenticator
- Microsoft Authenticator
- Authy
- 1Password
// Setup $setup = mfa('totp')->setup($user); // Verify $isValid = mfa('totp')->verify($user, $code); // Disable mfa('totp')->disable($user);
2. Email OTP
Send verification codes via email.
// Send challenge mfa('email_otp')->challenge($user); // Verify $isValid = mfa('email_otp')->verify($user, $code);
3. WebAuthn / Passkey
Hardware security keys and biometric authentication.
// Setup $options = mfa('webauthn')->setup($user); // Verify $isValid = mfa('webauthn')->verify($user, $credential);
Security Features
- Rate Limiting: Configurable max attempts and lockout
- Backup Codes: Emergency access codes for TOTP
- Remember Device: Optional trusted device feature
- Session Timeout: Automatic MFA session expiration
- Audit Logging: Track all MFA events
Events
Listen to MFA events:
use Mchuluq\LaravelMFA\Events\MFAEnabled; use Mchuluq\LaravelMFA\Events\MFAVerified; use Mchuluq\LaravelMFA\Events\MFAFailed; // In EventServiceProvider protected $listen = [ MFAEnabled::class => [ SendMFAEnabledNotification::class, ], MFAVerified::class => [ LogMFAVerification::class, ], ];
OTPHP 11 security update
This package now requires spomky-labs/otphp ^11.4.3 to exclude the vulnerable OTPHP 10 releases and OTPHP versions below 11.4.3. Applications that explicitly require OTPHP 10 must update that constraint. Consumers using OTPHP directly should review the upstream migration documentation.
Existing TOTP secrets and provisioning settings remain usable; users do not need to enroll again. The MFA window setting still counts whole periods: 1 accepts the previous, current, and next period. OTPHP 11's native verification argument now counts seconds and cannot directly represent this setting, so the driver checks each permitted period explicitly. Negative or non-integer window values now raise InvalidArgumentException.
Tests
After installing development dependencies, run composer test. Regression tests cover an RFC 6238 vector, existing secrets, provisioning settings, QR rendering, random secret generation, and period-window boundaries (including windows 0, 1, and 2 with periods 30 and 60 seconds).
Validated on PHP 8.3.36 / Laravel 12.70.1 inside sister-ng-php8-app, with OTPHP 11.4.3 and 11.5.0: 5 tests, 157 assertions pass on both versions. Composer validation, platform requirements, and dependency audit pass. Other supported PHP/Laravel combinations and database-backed MFA flows have not been tested in this change.
Applications can receive this fix through their normal remote Composer repository after the updated package commit is published. No local path repository is required.
License
The MIT License (MIT). Please see License File for more information.