π Plug & Play Laravel 2FA - Email OTP, SMS OTP, TOTP, WebAuthn/FIDO2, Recovery Codes with Multi-Auth Guard Support. Production-ready in 30 seconds!
webmonks/laravel-2fa is a Laravel package for π plug & play laravel 2fa - email otp, sms otp, totp, webauthn/fido2, recovery codes with multi-auth guard support. production-ready in 30 seconds!.
It currently has 2 GitHub stars and 33 downloads on Packagist (latest version 1.2.0).
Install it with composer require webmonks/laravel-2fa.
Discover more Laravel packages by webmonks
or browse all Laravel packages to compare alternatives.
Last updated
The definitive Laravel 2FA package with true plug-and-play architecture. Zero configuration required - works instantly with Laravel Mail, then scales to enterprise needs with WhatsApp, Voice, Push Notifications, and custom delivery providers.
Transform your Laravel authentication from basic to bulletproof in 30 seconds. Unlike other 2FA packages that force you into rigid patterns, Laravel 2FA v1.1 gives you the freedom to start simple and customize everything as your requirements evolve - now with global reach through WhatsApp, Voice calls, Push notifications, and intelligent fallback systems.
π 30-Second Setup: Install, migrate, protect routes - done. Email OTP works immediately with your existing Laravel Mail configuration.
π True Plug & Play: Start with zero configuration, then customize anything. No vendor lock-in, no forced dependencies, no architectural constraints.
π― Production Battle-Tested: 96 comprehensive tests, 227 assertions, extensive security features, and real-world deployment experience.
ποΈ Enterprise-Ready Architecture: Multi-auth support, device trust management, comprehensive rate limiting, audit logging, and extensible provider system.
composer require webmonks/laravel-2fa
php artisan two-factor:install
php artisan migrate
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use WebMonks\Laravel2FA\Contracts\TwoFactorAuthenticatable;
use WebMonks\Laravel2FA\Traits\HasTwoFactorAuthentication;
class User extends Authenticatable implements TwoFactorAuthenticatable
{
use HasTwoFactorAuthentication;
// Your existing model code...
}
// Protect routes (in routes/web.php)
Route::group(['middleware' => ['auth', '2fa']], function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::get('/sensitive-data', [DataController::class, 'show']);
});
// Enable 2FA for users (in your controller)
use WebMonks\Laravel2FA\Facades\TwoFactor;
// Email OTP (works immediately - zero configuration needed)
TwoFactor::enable($user, 'email');
// TOTP/Google Authenticator
TwoFactor::enable($user, 'totp');
$qrCodeUrl = TwoFactor::getTotpQrCodeUrl($user); // Show this QR to user
That's it! Your routes are now protected with email-based 2FA using Laravel's built-in mail system.
Laravel 2FA works instantly with your existing setup, then grows with your needs:
// Day 1: Email OTP (works immediately)
TwoFactor::enable($user, 'email');
TwoFactor::generateCode($user, 'email'); // Sends via Laravel Mail
// Day 30: Add SMS when ready
// .env: TWILIO_SID=xxx TWILIO_TOKEN=yyy TWILIO_FROM=+1234567890
TwoFactor::setPhoneNumber($user, '+15551234567');
TwoFactor::enable($user, 'sms');
// Day 60: Add WhatsApp for global users
TwoFactor::enable($user, 'whatsapp');
TwoFactor::generateCode($user, 'whatsapp');
// Day 90: Add Voice calls for accessibility
TwoFactor::enable($user, 'voice');
TwoFactor::generateCode($user, 'voice'); // Multi-language support
// Day 120: Add Push notifications for mobile apps
TwoFactor::enable($user, 'push');
TwoFactor::registerPushDevice($user, $fcmToken, 'android');
// Day 150: Add TOTP for power users
TwoFactor::enable($user, 'totp');
$qrCode = TwoFactor::getTotpQrCodeUrl($user);
// Day 180: Add device trust and recovery codes
$recoveryCodes = TwoFactor::generateRecoveryCodes($user);
TwoFactor::trustDevice($user, $deviceFingerprint);
# Install the package
composer require webmonks/laravel-2fa
# Run installation (publishes config, migrations)
php artisan two-factor:install
# Run migrations
php artisan migrate
# Publish config for customization (optional)
php artisan vendor:publish --tag=two-factor-config
# Publish views for UI customization (optional)
php artisan vendor:publish --tag=two-factor-views
composer require twilio/sdk
# .env
TWO_FACTOR_SMS_ENABLED=true
TWILIO_SID=your_account_sid
TWILIO_TOKEN=your_auth_token
TWILIO_FROM=+15551234567
composer require vonage/client
# .env
TWO_FACTOR_SMS_ENABLED=true
TWO_FACTOR_SMS_DRIVER=vonage
VONAGE_API_KEY=your_api_key
VONAGE_API_SECRET=your_api_secret
VONAGE_FROM=YourApp
composer require aws/aws-sdk-php
# .env
TWO_FACTOR_SMS_ENABLED=true
TWO_FACTOR_SMS_DRIVER=aws-sns
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_DEFAULT_REGION=us-east-1
use WebMonks\Laravel2FA\Facades\TwoFactor;
// Enable email 2FA (works immediately with Laravel Mail)
TwoFactor::enable($user, 'email');
// Generate and send code
TwoFactor::generateCode($user, 'email');
// User receives: "Your verification code is: 123456"
// Verify code
$isValid = TwoFactor::verifyCode($user, '123456', 'email');
// Check status
$isEnabled = TwoFactor::isEnabled($user, 'email');
// Set user's phone number
TwoFactor::setPhoneNumber($user, '+15551234567');
// Enable SMS 2FA
TwoFactor::enable($user, 'sms');
// Generate and send SMS
$sent = TwoFactor::generateCode($user, 'sms');
if ($sent) {
return response()->json(['message' => 'SMS sent to your phone']);
}
// Verify SMS code
$isValid = TwoFactor::verifyCode($user, $request->input('code'), 'sms');
// Enable TOTP
TwoFactor::enable($user, 'totp');
// Get QR code URL for setup
$qrCodeUrl = TwoFactor::getTotpQrCodeUrl($user);
// Display this QR code to user for scanning with Google Authenticator
// Get setup key (alternative to QR code)
$setupKey = TwoFactor::getTotpSecretKey($user);
// Verify TOTP code
$isValid = TwoFactor::verifyCode($user, '123456', 'totp');
// Generate recovery codes
$codes = TwoFactor::generateRecoveryCodes($user);
// Returns: ['a1b2c3d4e5', 'f6g7h8i9j0', ...] (8 codes by default)
// Show codes to user for safe storage
foreach ($codes as $code) {
echo "Recovery code: {$code}\n";
}
// Verify recovery code
$isValid = TwoFactor::verifyRecoveryCode($user, 'a1b2c3d4e5');
// Check remaining recovery codes
$remaining = TwoFactor::getRemainingRecoveryCodes($user);
// Generate device fingerprint (your implementation)
$deviceFingerprint = hash('sha256', $request->ip() . $request->userAgent());
// Trust current device
TwoFactor::trustDevice($user, $deviceFingerprint);
// Check if device is trusted
if (TwoFactor::isDeviceTrusted($user, $deviceFingerprint)) {
// Skip 2FA for trusted device
return redirect('/dashboard');
}
// Remove trusted device
TwoFactor::removeTrustedDevice($user, $deviceFingerprint);
// Get all trusted devices
$trustedDevices = TwoFactor::getTrustedDevices($user);
Laravel 2FA v1.1 introduces powerful new authentication methods for enhanced security and global reach.
Send verification codes via WhatsApp using Twilio WhatsApp or WhatsApp Business API.
For Twilio WhatsApp:
# Install Twilio SDK
composer require twilio/sdk
# .env
TWO_FACTOR_WHATSAPP_ENABLED=true
TWILIO_SID=your_account_sid
TWILIO_TOKEN=your_auth_token
TWILIO_WHATSAPP_FROM=whatsapp:+14155238886
For WhatsApp Business API:
# .env
TWO_FACTOR_WHATSAPP_ENABLED=true
TWO_FACTOR_WHATSAPP_DRIVER=whatsapp_business
WHATSAPP_BUSINESS_ACCESS_TOKEN=your_access_token
WHATSAPP_BUSINESS_PHONE_NUMBER_ID=your_phone_number_id
WHATSAPP_BUSINESS_API_VERSION=v18.0
use WebMonks\Laravel2FA\Facades\TwoFactor;
// Set user's WhatsApp number
TwoFactor::setPhoneNumber($user, '+15551234567');
// Enable WhatsApp 2FA
TwoFactor::enable($user, 'whatsapp');
// Generate and send WhatsApp code
$sent = TwoFactor::generateCode($user, 'whatsapp');
if ($sent) {
return response()->json(['message' => 'WhatsApp code sent successfully']);
}
// Verify WhatsApp code
$isValid = TwoFactor::verifyCode($user, $request->input('code'), 'whatsapp');
// Custom message template
$messageTemplate = 'Your *{app_name}* verification code is: *{code}*\n\nExpires in {expiry_minutes} minutes. π';
Deliver verification codes via voice calls with multi-language support and customizable voices.
# .env
TWO_FACTOR_VOICE_ENABLED=true
TWILIO_SID=your_account_sid
TWILIO_TOKEN=your_auth_token
TWILIO_VOICE_FROM=+15551234567
# Voice settings
TWO_FACTOR_VOICE_LANGUAGE=en-US
TWO_FACTOR_VOICE_TYPE=woman
TWO_FACTOR_VOICE_SPEED=1.0
TWO_FACTOR_VOICE_REPEAT_COUNT=2
// Enable voice call 2FA
TwoFactor::enable($user, 'voice');
// Generate and make voice call
$called = TwoFactor::generateCode($user, 'voice');
if ($called) {
return response()->json(['message' => 'Voice call initiated']);
}
// Verify voice code
$isValid = TwoFactor::verifyCode($user, $request->input('code'), 'voice');
// Supported languages and voices
$languages = ['en-US', 'es-ES', 'fr-FR', 'de-DE', 'it-IT', 'pt-BR', 'ru-RU', 'ja-JP', 'ko-KR', 'zh-CN'];
$voices = ['woman', 'man', 'alice']; // Alice supports more languages
Enhanced SMS support with Vonage (formerly Nexmo) and AWS SNS, plus intelligent fallback chains.
# Install Vonage SDK
composer require vonage/client
# .env
TWO_FACTOR_SMS_ENABLED=true
TWO_FACTOR_SMS_DRIVER=vonage
VONAGE_API_KEY=your_api_key
VONAGE_API_SECRET=your_api_secret
VONAGE_FROM=YourApp
# Install AWS SDK
composer require aws/aws-sdk-php
# .env
TWO_FACTOR_SMS_ENABLED=true
TWO_FACTOR_SMS_DRIVER=aws-sns
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_DEFAULT_REGION=us-east-1
AWS_SNS_SENDER_ID=YourApp
Configure fallback chains for maximum reliability:
// config/two-factor.php
'sms' => [
'driver' => 'twilio',
'fallback_drivers' => ['vonage', 'aws-sns'], // Fallback order
// Additional fallback settings
'fallback_delay' => 30, // Wait 30s before trying fallback
'max_fallback_attempts' => 2,
],
// Usage remains the same - fallback is automatic
TwoFactor::generateCode($user, 'sms'); // Will try Twilio β Vonage β AWS SNS
Implement push notification-based 2FA with approval workflows for mobile applications.
# .env
TWO_FACTOR_PUSH_ENABLED=true
TWO_FACTOR_PUSH_DRIVER=fcm
FCM_SERVER_KEY=your_server_key
FCM_SENDER_ID=your_sender_id
FCM_PROJECT_ID=your_project_id
FCM_CREDENTIALS_FILE=/path/to/service-account.json
# .env
TWO_FACTOR_PUSH_ENABLED=true
TWO_FACTOR_PUSH_DRIVER=apns
APNS_KEY_ID=your_key_id
APNS_TEAM_ID=your_team_id
APNS_APP_BUNDLE_ID=com.yourapp.bundle
APNS_PRIVATE_KEY_PATH=/path/to/AuthKey_XXXXX.p8
APNS_PRODUCTION=false
// Register user's push device
TwoFactor::registerPushDevice($user, $fcmToken, 'android', [
'device_name' => 'John\'s iPhone',
'device_model' => 'iPhone 13',
'app_version' => '1.2.0',
]);
// Enable push 2FA
TwoFactor::enable($user, 'push');
// Send push notification for approval
$sent = TwoFactor::generateCode($user, 'push');
if ($sent) {
return response()->json([
'message' => 'Push notification sent',
'timeout' => 300, // 5 minutes to approve
]);
}
// Check approval status
$isApproved = TwoFactor::isPushApproved($user, $challengeId);
// Approve push notification (from mobile app)
TwoFactor::approvePushChallenge($user, $challengeId, [
'biometric_used' => true,
'location' => ['lat' => 37.7749, 'lng' => -122.4194],
'device_info' => ['battery' => 85, 'network' => 'wifi'],
]);
// Deny push notification
TwoFactor::denyPushChallenge($user, $challengeId, 'User denied');
Extend Laravel 2FA with custom delivery methods like Slack, Discord, or Telegram.
# .env
TWO_FACTOR_CUSTOM_DELIVERY_ENABLED=true
SLACK_2FA_WEBHOOK_URL=https://hooks.slack.com/services/xxx/yyy/zzz
SLACK_2FA_CHANNEL=#security
SLACK_2FA_USERNAME=2FA Bot
// Create custom Slack provider
class SlackTwoFactorProvider extends AbstractCustomProvider
{
public function send(string $to, string $message, array $options = []): bool
{
$payload = [
'channel' => $this->config['channel'] ?? '#security',
'username' => $this->config['username'] ?? '2FA Bot',
'text' => "π 2FA Code for {$to}: `{$message}`",
'icon_emoji' => ':lock:',
];
return Http::post($this->config['webhook_url'], $payload)->successful();
}
}
// Register in service provider
$this->app->bind('two-factor.custom.slack', SlackTwoFactorProvider::class);
// Usage
TwoFactor::enableCustomDelivery($user, 'slack', ['channel' => '@john.doe']);
TwoFactor::generateCode($user, 'slack');
# .env
DISCORD_2FA_WEBHOOK_URL=https://discord.com/api/webhooks/xxx/yyy
DISCORD_2FA_USERNAME=2FA Bot
class DiscordTwoFactorProvider extends AbstractCustomProvider
{
public function send(string $to, string $message, array $options = []): bool
{
$payload = [
'username' => $this->config['username'] ?? '2FA Bot',
'content' => "π **2FA Verification Code**\nUser: {$to}\nCode: `{$message}`\nβ° Expires in 10 minutes",
'embeds' => [[
'color' => 0x00ff00,
'title' => 'π Two-Factor Authentication',
'description' => "Your verification code: **{$message}**",
'timestamp' => now()->toISOString(),
]],
];
return Http::post($this->config['webhook_url'], $payload)->successful();
}
}
# .env
TELEGRAM_BOT_TOKEN=your_bot_token
TELEGRAM_CHAT_ID=your_chat_id
class TelegramTwoFactorProvider extends AbstractCustomProvider
{
public function send(string $to, string $message, array $options = []): bool
{
$payload = [
'chat_id' => $this->config['chat_id'],
'text' => "π *2FA Verification Code*\n\nUser: {$to}\nCode: `{$message}`\n\nβ° Expires in 10 minutes",
'parse_mode' => 'Markdown',
'reply_markup' => json_encode([
'inline_keyboard' => [[
['text' => 'β
Approved', 'callback_data' => "approve_{$message}"],
['text' => 'β Deny', 'callback_data' => "deny_{$message}"],
]],
]),
];
$url = "https://api.telegram.org/bot{$this->config['bot_token']}/sendMessage";
return Http::post($url, $payload)->successful();
}
}
Configure sophisticated fallback chains for maximum delivery reliability.
// config/two-factor.php
'custom_delivery' => [
'fallback_chain' => [
'enabled' => true,
'primary_to_fallback_delay' => 30, // seconds
'chains' => [
// SMS fallback chain
'sms_fallback' => ['sms', 'whatsapp', 'voice', 'email'],
// Email fallback chain
'email_fallback' => ['email', 'push'],
// Push fallback chain
'push_fallback' => ['push', 'sms', 'email'],
// Custom enterprise chain
'enterprise_fallback' => ['push', 'whatsapp', 'voice', 'slack', 'email'],
],
],
],
// Automatic fallback usage
TwoFactor::enableFallbackChain($user, 'enterprise_fallback');
TwoFactor::generateCode($user, 'sms'); // Will try entire enterprise chain if needed
# WhatsApp Configuration
TWO_FACTOR_WHATSAPP_ENABLED=false
TWO_FACTOR_WHATSAPP_DRIVER=twilio
TWILIO_WHATSAPP_FROM=whatsapp:+14155238886
WHATSAPP_BUSINESS_ACCESS_TOKEN=your_token
WHATSAPP_BUSINESS_PHONE_NUMBER_ID=your_phone_id
# Voice Call Configuration
TWO_FACTOR_VOICE_ENABLED=false
TWILIO_VOICE_FROM=+15551234567
TWO_FACTOR_VOICE_LANGUAGE=en-US
TWO_FACTOR_VOICE_TYPE=woman
TWO_FACTOR_VOICE_SPEED=1.0
# Additional SMS Providers
TWO_FACTOR_SMS_DRIVER=twilio
TWO_FACTOR_SMS_FALLBACK_DRIVERS=vonage,aws-sns
VONAGE_API_KEY=your_api_key
VONAGE_API_SECRET=your_api_secret
AWS_SNS_SENDER_ID=YourApp
# Push Notifications
TWO_FACTOR_PUSH_ENABLED=false
TWO_FACTOR_PUSH_DRIVER=fcm
FCM_SERVER_KEY=your_server_key
FCM_PROJECT_ID=your_project_id
APNS_KEY_ID=your_key_id
APNS_TEAM_ID=your_team_id
APNS_APP_BUNDLE_ID=com.yourapp.bundle
# Custom Delivery
TWO_FACTOR_CUSTOM_DELIVERY_ENABLED=false
SLACK_2FA_WEBHOOK_URL=https://hooks.slack.com/services/xxx
DISCORD_2FA_WEBHOOK_URL=https://discord.com/api/webhooks/xxx
TELEGRAM_BOT_TOKEN=your_bot_token
TELEGRAM_CHAT_ID=your_chat_id
# Advanced Settings
TWO_FACTOR_FALLBACK_CHAIN_ENABLED=false
TWO_FACTOR_FALLBACK_DELAY=30
Laravel 2FA natively supports multiple authentication guards for complex applications:
// config/two-factor.php
'guards' => [
'web' => [
'enabled' => true,
'model' => \App\Models\User::class,
'routes' => [
'challenge' => '/two-factor/challenge',
'verify' => '/two-factor/verify',
],
],
'admin' => [
'enabled' => true,
'model' => \App\Models\Admin::class,
'routes' => [
'challenge' => '/admin/two-factor/challenge',
'verify' => '/admin/two-factor/verify',
],
],
'api' => [
'enabled' => true,
'model' => \App\Models\User::class,
'stateless' => true, // No sessions for API
],
'customer' => [
'enabled' => true,
'model' => \App\Models\Customer::class,
'routes' => [
'challenge' => '/customer/two-factor/challenge',
'verify' => '/customer/two-factor/verify',
],
],
],
// Enable 2FA for different guards
TwoFactor::enable($user, 'email', 'web');
TwoFactor::enable($admin, 'totp', 'admin');
TwoFactor::enable($customer, 'sms', 'customer');
// Guard-specific middleware
Route::group(['middleware' => ['auth:admin', '2fa:admin']], function () {
Route::get('/admin/dashboard', [AdminController::class, 'dashboard']);
});
Route::group(['middleware' => ['auth:customer', '2fa:customer']], function () {
Route::get('/customer/profile', [CustomerController::class, 'profile']);
});
// API routes with stateless 2FA
Route::middleware(['auth:sanctum', '2fa:api'])->group(function () {
Route::get('/api/user', function (Request $request) {
return $request->user();
});
});
// Verify codes with specific guard
$isValid = TwoFactor::verifyCode($admin, $code, 'totp', 'admin');
$isValid = TwoFactor::verifyCode($user, $code, 'email', 'api');
// Built-in rate limiting (configurable)
'rate_limiting' => [
'enabled' => true,
'max_attempts' => 5, // 5 attempts
'decay_minutes' => 15, // per 15 minutes
],
// SMS-specific rate limiting
'sms' => [
'rate_limiting' => [
'per_phone_number' => [
'max_attempts' => 10, // 10 SMS per phone
'decay_minutes' => 60, // per hour
],
'global' => [
'max_attempts' => 1000, // 1000 SMS total
'decay_minutes' => 60, // per hour
],
],
],
// Enable comprehensive logging
'logging' => [
'enabled' => true,
'channel' => 'stack', // Uses Laravel's logging
'events' => [
'enabled' => true, // Log when 2FA enabled
'disabled' => true, // Log when 2FA disabled
'verified' => true, // Log successful verifications
'failed' => true, // Log failed attempts
'recovery_used' => true, // Log recovery code usage
],
],
// Publish views for customization
php artisan vendor:publish --tag=two-factor-views
// Customize email templates in:
// resources/views/vendor/two-factor/emails/code.blade.php
// resources/views/vendor/two-factor/emails/code-text.blade.php
<?php
namespace App\Providers\Sms;
use WebMonks\Laravel2FA\Contracts\SmsProvider;
use WebMonks\Laravel2FA\Providers\Sms\AbstractSmsProvider;
class CustomSmsProvider extends AbstractSmsProvider
{
public function send(string $to, string $message, array $options = []): bool
{
// Your custom SMS logic here
$response = Http::post('https://api.yoursms.com/send', [
'api_key' => $this->config['api_key'],
'to' => $to,
'message' => $message,
]);
return $response->successful();
}
public function getName(): string
{
return 'custom';
}
public function getMaxMessageLength(): int
{
return 160;
}
public function getRequiredConfig(): array
{
return ['api_key', 'api_secret'];
}
}
Register in your service provider:
// AppServiceProvider.php
public function register()
{
$this->app->bind('two-factor.sms.custom', function ($app) {
$config = config('two-factor.sms.drivers.custom', []);
return new CustomSmsProvider($config);
});
}
For API applications, Laravel 2FA provides structured JSON responses:
Route::middleware(['auth:sanctum', '2fa:api'])->group(function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
Route::post('/sensitive-action', [ApiController::class, 'sensitiveAction']);
});
When 2FA is required, the middleware returns:
{
"message": "Two-factor authentication required",
"error": "two_factor_required",
"available_methods": ["email", "sms", "whatsapp", "voice", "push", "totp"],
"challenge_url": "/api/two-factor/challenge"
}
// Generate codes via API
POST /api/two-factor/generate
{
"method": "email" // or "sms", "whatsapp", "voice", "push", "totp"
}
// Verify codes via API
POST /api/two-factor/verify
{
"code": "123456",
"method": "email"
}
// Push notification approval API
POST /api/two-factor/push/approve
{
"challenge_id": "uuid-challenge-id",
"approved": true,
"biometric_used": true
}
// Get user 2FA status
GET /api/two-factor/status
# Run all tests
composer test
# Run with coverage
composer test-coverage
# Run specific test suite
./vendor/bin/pest tests/Feature/EmailOtpTest.php
./vendor/bin/pest tests/Feature/SmsOtpTest.php
./vendor/bin/pest tests/Feature/TotpTest.php
use Illuminate\Support\Facades\Notification;
use WebMonks\Laravel2FA\Notifications\TwoFactorSmsCode;
use WebMonks\Laravel2FA\Facades\TwoFactor;
public function test_email_otp_flow()
{
Mail::fake();
// Enable email 2FA
TwoFactor::enable($this->user, 'email');
// Generate code
TwoFactor::generateCode($this->user, 'email');
// Assert email was sent
Mail::assertSent(TwoFactorCodeMail::class);
// Verify code works
$code = TwoFactor::getLastGeneratedCode($this->user, 'email');
$this->assertTrue(TwoFactor::verifyCode($this->user, $code, 'email'));
}
public function test_sms_otp_flow()
{
Notification::fake();
// Setup SMS
TwoFactor::setPhoneNumber($this->user, '+15551234567');
TwoFactor::enable($this->user, 'sms');
// Generate SMS code
TwoFactor::generateCode($this->user, 'sms');
// Assert SMS notification sent
Notification::assertSentTo($this->user, TwoFactorSmsCode::class);
}
Laravel 2FA includes helpful Artisan commands for management:
# Install package (publishes config & migrations)
php artisan two-factor:install
# Enable 2FA for a user
php artisan two-factor:enable "App\Models\User" 1 --method=email
php artisan two-factor:enable "App\Models\Admin" 5 --method=totp --guard=admin
# Disable 2FA for a user
php artisan two-factor:disable "App\Models\User" 1
php artisan two-factor:disable "App\Models\Admin" 5 --guard=admin
# Check 2FA status
php artisan two-factor:status "App\Models\User" 1
php artisan two-factor:status --all
php artisan two-factor:status --guard=admin
# Generate recovery codes
php artisan two-factor:recovery-codes "App\Models\User" 1
// config/two-factor.php
'default_method' => 'email',
'enabled_methods' => [
'email' => true, // Email OTP (zero config)
'sms' => false, // SMS OTP (requires provider)
'totp' => true, // TOTP/Google Authenticator
'recovery_codes' => true, // Recovery codes
],
'email' => [
'length' => 6, // Code length
'expire_minutes' => 10, // Code expiration
'throttle_minutes' => 1, // Send throttling
'max_attempts' => 5, // Max verification attempts
'queue' => 'default', // Queue for sending emails
],
'sms' => [
'length' => 6,
'expire_minutes' => 10,
'driver' => 'twilio', // SMS provider
'message_template' => 'Your {app_name} code: {code}',
],
'totp' => [
'issuer' => 'YourApp', // App name in authenticator
'algorithm' => 'sha1', // TOTP algorithm
'digits' => 6, // Code digits
'period' => 30, // Code validity period
'window' => 1, // Time window tolerance
],
'recovery_codes' => [
'count' => 8, // Number of recovery codes
'length' => 10, // Recovery code length
],
# Core settings
TWO_FACTOR_DEFAULT_METHOD=email
TWO_FACTOR_EMAIL_ENABLED=true
TWO_FACTOR_SMS_ENABLED=false
TWO_FACTOR_TOTP_ENABLED=true
# Email settings
TWO_FACTOR_EMAIL_OTP_LENGTH=6
TWO_FACTOR_EMAIL_EXPIRE_MINUTES=10
TWO_FACTOR_EMAIL_MAX_ATTEMPTS=5
# SMS settings (Twilio example)
TWILIO_SID=your_account_sid
TWILIO_TOKEN=your_auth_token
TWILIO_FROM=+15551234567
# Rate limiting
TWO_FACTOR_RATE_LIMITING_ENABLED=true
TWO_FACTOR_RATE_LIMIT_MAX_ATTEMPTS=5
TWO_FACTOR_RATE_LIMIT_DECAY_MINUTES=15
# Security
TWO_FACTOR_ENCRYPTION_ENABLED=true
TWO_FACTOR_LOGGING_ENABLED=true
TWO_FACTOR_REMEMBER_DEVICE_DAYS=30
// Email & SMS can be queued for better performance
'email' => [
'queue' => true,
'queue_name' => 'notifications',
],
'sms' => [
'queue' => true,
'queue_name' => 'sms',
],
// Add indexes for better performance (included in migrations)
Schema::table('two_factor_auth', function (Blueprint $table) {
$table->index(['user_id', 'user_type']);
$table->index(['expires_at']);
$table->index(['created_at']);
});
// Cache TOTP secrets and settings for performance
'totp' => [
'cache_enabled' => true,
'cache_ttl' => 3600, // 1 hour
],
// Multi-layer rate limiting
'rate_limiting' => [
'global' => [
'max_attempts' => 1000, // Global limit
'decay_minutes' => 60,
],
'per_user' => [
'max_attempts' => 10, // Per user limit
'decay_minutes' => 60,
],
'per_ip' => [
'max_attempts' => 50, // Per IP limit
'decay_minutes' => 60,
],
],
// Check Laravel Mail configuration
php artisan config:cache
php artisan queue:work
// Test Laravel Mail directly
Mail::to('[email protected]')->send(new TestMail());
// Check 2FA logs
tail -f storage/logs/laravel.log | grep "2fa"
// Verify SMS provider credentials
php artisan tinker
> config('two-factor.sms.drivers.twilio')
// Test provider connection
> TwoFactor::testSmsProvider('twilio')
// Check phone number format
> PhoneNumberFormatter::format('+1-555-123-4567', 'US')
// Increase time window tolerance
'totp' => [
'window' => 2, // Allow Β±2 time periods (Β±60 seconds)
],
// Check server time synchronization
date_default_timezone_set('UTC');
// Test WhatsApp provider credentials
php artisan tinker
> config('two-factor.whatsapp.drivers.twilio')
// Check WhatsApp sandbox setup (Twilio)
> TwoFactor::testWhatsAppProvider('twilio')
// Verify WhatsApp Business API credentials
> Http::get('https://graph.facebook.com/v18.0/{phone-number-id}', [
'access_token' => config('two-factor.whatsapp.drivers.whatsapp_business.access_token')
]);
Common WhatsApp Issues:
+1234567890)// Test voice provider
> TwoFactor::testVoiceProvider('twilio')
// Check voice capabilities for phone number
> TwoFactor::checkVoiceCapabilities('+15551234567')
// Test TwiML generation
> TwoFactor::generateVoiceTwiML('123456', ['language' => 'en-US'])
Common Voice Issues:
// Test FCM credentials
> TwoFactor::testFCMProvider()
// Test APNS connection
> TwoFactor::testAPNSProvider()
// Check device registration
> TwoFactor::checkPushDeviceRegistration($user, $deviceToken)
// Validate push payload
> TwoFactor::validatePushPayload($payload)
Common Push Issues:
// Test fallback chain
> TwoFactor::testSMSFallbackChain(['twilio', 'vonage', 'aws-sns'])
// Check provider status
> TwoFactor::checkProviderStatus('vonage')
> TwoFactor::checkProviderStatus('aws-sns')
// View fallback logs
> TwoFactor::getFallbackLogs($user, 'sms')
Common Fallback Issues:
// Test Slack webhook
> Http::post(config('two-factor.custom_delivery.providers.slack.webhook_url'), [
'text' => 'Test message from Laravel 2FA'
]);
// Test Discord webhook
> TwoFactor::testCustomProvider('discord')
// Test Telegram bot
> TwoFactor::testTelegramBot()
Common Custom Provider Issues:
# Enable detailed logging for all new features
TWO_FACTOR_LOGGING_ENABLED=true
TWILIO_DEBUG=true
TWILIO_WHATSAPP_DEBUG=true
TWILIO_VOICE_DEBUG=true
FCM_DEBUG=true
APNS_DEBUG=true
VONAGE_DEBUG=true
AWS_SNS_DEBUG=true
LOG_LEVEL=debug
# Enable test modes
TWO_FACTOR_WHATSAPP_TESTING=true
TWO_FACTOR_VOICE_TESTING=true
TWO_FACTOR_PUSH_TESTING=true
TWO_FACTOR_SMS_TESTING=true
// Monitor delivery success rates
$stats = TwoFactor::getDeliveryStats($user, 'last_30_days');
// Track provider performance
$performance = TwoFactor::getProviderPerformance(['twilio', 'vonage', 'fcm']);
// Get fallback usage statistics
$fallbackStats = TwoFactor::getFallbackStatistics();
// Monitor costs (if cost tracking enabled)
$costs = TwoFactor::getCostAnalysis('this_month');
We welcome contributions! Please see our Contributing Guide for details.
git clone https://github.com/webmonks-technologies/laravel-2fa.git
cd laravel-2fa
composer install
cp .env.example .env
./vendor/bin/pest
If you discover a security vulnerability, please send an email to [email protected]. All security vulnerabilities will be promptly addressed.
Laravel 2FA is open-sourced software licensed under the MIT License.
Ready to secure your Laravel application?
composer require webmonks/laravel-2fa
php artisan two-factor:install
php artisan migrate
From zero to bulletproof authentication in 30 seconds. π