webmonks/laravel-2fa

🔐 Plug & Play Laravel 2FA - Email OTP, SMS OTP, TOTP, WebAuthn/FIDO2, Recovery Codes with Multi-Auth Guard Support. Production-ready in 30 seconds!

1.2.0 2025-09-26 04:51 UTC

This package is auto-updated.

Last update: 2025-09-26 05:29:29 UTC


README

Latest Version on Packagist GitHub Tests Action Status Total Downloads PHP Version Require License

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.

Why Laravel 2FA?

🚀 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.

Key Features

🔐 Complete 2FA Methods

  • Email OTP (zero-config) - Works instantly with Laravel Mail
  • SMS OTP - Twilio, Vonage/Nexmo, AWS SNS with fallback chains
  • WhatsApp OTP - Twilio WhatsApp & WhatsApp Business API
  • Voice Call OTP - Multi-language voice calls with customizable voices
  • Push Notifications - FCM (Android/iOS/Web) & APNS (iOS) with approval workflows
  • TOTP/Google Authenticator - Time-based codes with QR generation
  • Recovery Codes - Secure backup authentication system

🛡️ Enterprise Security

  • Multi-Auth Guards: Native support for web, admin, api, customer - any authentication guard
  • Advanced Fallback System: Multi-provider chains with intelligent failover
  • Device Trust Management: Remember trusted devices with configurable expiration
  • Rate Limiting: Brute force protection with configurable thresholds
  • End-to-End Encryption: All sensitive data encrypted at rest
  • Comprehensive Audit Logging: Track all 2FA events and security incidents

🔧 Developer Experience

  • True Plug & Play: Works in 30 seconds with zero configuration
  • 100% Customizable: Override providers, templates, logic, UI - or use sensible defaults
  • Custom Delivery Providers: Slack, Discord, Telegram integration examples
  • Extensible Architecture: Create custom providers for any delivery method
  • 95%+ Test Coverage: Production-ready with PestPHP testing framework
  • Laravel 10, 11, 12+ Ready: Modern Laravel compatibility with future-proof architecture

Requirements

  • PHP: 8.1+ minimum
  • Laravel: 10.0+ (supports 11.x, 12.x)
  • Optional Providers: Twilio SDK, Vonage, AWS SNS, FCM, APNS for enhanced 2FA methods

Quick Start (30 Seconds)

1. Install & Setup

composer require webmonks/laravel-2fa
php artisan two-factor:install
php artisan migrate

2. Prepare Your User Model

<?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...
}

3. Protect Routes & Enable 2FA

// 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.

Zero Configuration Philosophy

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);

Complete Installation Guide

Basic Installation

# Install the package
composer require webmonks/laravel-2fa

# Run installation (publishes config, migrations)
php artisan two-factor:install

# Run migrations
php artisan migrate

Optional: Publish Configuration

# 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

Optional: SMS Provider Setup

For Twilio (Recommended)

composer require twilio/sdk
# .env
TWO_FACTOR_SMS_ENABLED=true
TWILIO_SID=your_account_sid
TWILIO_TOKEN=your_auth_token
TWILIO_FROM=+15551234567

For Vonage/Nexmo

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

For AWS SNS

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

Usage Examples

Email OTP (Zero Configuration)

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');

SMS OTP (Once Provider Configured)

// 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');

TOTP/Google Authenticator

// 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');

Recovery Codes

// 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);

Device Trust Management

// 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);

New in v1.1: Advanced 2FA Methods

Laravel 2FA v1.1 introduces powerful new authentication methods for enhanced security and global reach.

WhatsApp OTP

Send verification codes via WhatsApp using Twilio WhatsApp or WhatsApp Business API.

Configuration

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

Usage

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. 🔐';

Voice Call OTP

Deliver verification codes via voice calls with multi-language support and customizable voices.

Configuration

# .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

Usage

// 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

Additional SMS Providers

Enhanced SMS support with Vonage (formerly Nexmo) and AWS SNS, plus intelligent fallback chains.

Vonage/Nexmo Configuration

# 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

AWS SNS Configuration

# 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

SMS Provider Fallback

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

Push Notifications

Implement push notification-based 2FA with approval workflows for mobile applications.

FCM (Firebase Cloud Messaging) Configuration

# .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

APNS (Apple Push Notification) Configuration

# .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

Push Notification Usage

// 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');

Custom Delivery Providers

Extend Laravel 2FA with custom delivery methods like Slack, Discord, or Telegram.

Slack Integration Example

# .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');

Discord Integration Example

# .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();
    }
}

Telegram Bot Integration

# .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();
    }
}

Advanced Fallback Configuration

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

Environment Variables for v1.1 Features

# 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

Multi-Auth Guard Support

Laravel 2FA natively supports multiple authentication guards for complex applications:

Configuration

// 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',
        ],
    ],
],

Usage with Guards

// 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');

Advanced Features

Rate Limiting & Security

// 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
        ],
    ],
],

Audit Logging

// 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
    ],
],

Custom Email Templates

// 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

Custom SMS Provider

<?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);
    });
}

API & JSON Responses

For API applications, Laravel 2FA provides structured JSON responses:

API Middleware

Route::middleware(['auth:sanctum', '2fa:api'])->group(function () {
    Route::get('/user', function (Request $request) {
        return $request->user();
    });

    Route::post('/sensitive-action', [ApiController::class, 'sensitiveAction']);
});

JSON Response Format

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"
}

API Endpoints

// 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

Testing

Running Tests

# 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

Test Your Integration

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);
}

Artisan Commands

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

Configuration Reference

Core Configuration

// 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
],

Environment Variables

# 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

Performance & Optimization

Queue Configuration

// Email & SMS can be queued for better performance
'email' => [
    'queue' => true,
    'queue_name' => 'notifications',
],

'sms' => [
    'queue' => true,
    'queue_name' => 'sms',
],

Database Optimization

// 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']);
});

Caching

// Cache TOTP secrets and settings for performance
'totp' => [
    'cache_enabled' => true,
    'cache_ttl' => 3600, // 1 hour
],

Security Considerations

Data Protection

  • Encryption: All sensitive data (secrets, codes) encrypted at rest
  • Secure Deletion: Used codes and expired data automatically purged
  • No Plain Text: Codes never stored in plain text, always hashed
  • Secure Transmission: HTTPS recommended for all 2FA operations

Rate Limiting

// 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,
    ],
],

Best Practices

  1. Use HTTPS: Always serve your application over HTTPS
  2. Secure Sessions: Use secure session configuration
  3. Monitor Logs: Enable audit logging and monitor for suspicious activity
  4. Regular Updates: Keep the package and dependencies updated
  5. Backup Recovery Codes: Ensure users safely store recovery codes
  6. Test Thoroughly: Test 2FA flows in staging before production

Troubleshooting

Common Issues

Email OTP Not Sending

// Check Laravel Mail configuration
php artisan config:cache
php artisan queue:work

// Test Laravel Mail directly
Mail::to('test@example.com')->send(new TestMail());

// Check 2FA logs
tail -f storage/logs/laravel.log | grep "2fa"

SMS Issues

// 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')

TOTP Sync Issues

// Increase time window tolerance
'totp' => [
    'window' => 2, // Allow ±2 time periods (±60 seconds)
],

// Check server time synchronization
date_default_timezone_set('UTC');

WhatsApp Issues

// 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:

  • Sandbox not configured: Ensure WhatsApp sandbox is properly set up in Twilio Console
  • Business API not approved: WhatsApp Business API requires Meta approval for production
  • Invalid phone format: WhatsApp requires E.164 format (+1234567890)
  • Template violations: Messages must follow WhatsApp template policies

Voice Call Issues

// 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:

  • Number not voice-enabled: Some numbers don't support voice calls
  • Language not supported: Check available languages for your region
  • Audio quality issues: Adjust speed and voice type settings
  • International restrictions: Some countries have voice calling restrictions

Push Notification 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:

  • Invalid FCM server key: Ensure server key matches project
  • APNS certificate expired: Check certificate validity
  • Device token invalid: Tokens expire and need refresh
  • Network issues: Push services require stable internet connection
  • App not in foreground: Some systems require app to be active

SMS Provider Fallback 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:

  • All providers failing: Check network connectivity and credentials
  • Infinite fallback loops: Ensure fallback_drivers doesn't include primary driver
  • Quota exceeded: Monitor usage limits for each provider
  • Configuration mismatch: Verify each provider's required settings

Custom Delivery Provider 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:

  • Webhook URL invalid: Verify webhook URLs are accessible
  • Authentication failed: Check API keys and tokens
  • Rate limiting: Custom providers may have rate limits
  • Message formatting: Some providers require specific message formats

Debug Mode

# 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

Monitoring & Analytics

// 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');

Support Channels

Roadmap

✅ Version 1.1 (Released - January 2025)

  • ✅ WhatsApp OTP: Twilio WhatsApp & WhatsApp Business API integration
  • ✅ Voice Call OTP: Multi-language voice calls with Twilio
  • ✅ Additional SMS Providers: Vonage/Nexmo & AWS SNS support
  • ✅ Push Notifications: FCM (Android/iOS/Web) & APNS (iOS) support
  • ✅ Custom Delivery Providers: Slack, Discord, Telegram integration examples
  • ✅ Advanced Fallback System: Multi-provider fallback chains
  • ✅ Enhanced Security: Improved rate limiting and monitoring

Version 1.2 (Q2 2025)

  • Admin Dashboard: Web UI for 2FA management and analytics
  • Enhanced Analytics: Usage statistics, success rates, and cost tracking
  • Backup Authentication: Hardware security keys (WebAuthn/FIDO2)
  • Mobile SDK: React Native and Flutter SDK for push notifications

Version 2.0 (Q3 2025)

  • Biometric Support: Touch ID, Face ID integration
  • Risk-Based Authentication: AI-powered adaptive authentication
  • Multi-Tenant Support: SaaS application features
  • Advanced Audit: Compliance reporting and forensic analysis

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

git clone https://github.com/webmonks-technologies/laravel-2fa.git
cd laravel-2fa
composer install
cp .env.example .env
./vendor/bin/pest

Code Standards

  • PSR-12: Follow PSR-12 coding standards
  • Tests: All features must include tests
  • Documentation: Update docs for new features
  • Backwards Compatibility: Maintain BC unless major version

Security Vulnerabilities

If you discover a security vulnerability, please send an email to darshan@webmonks.in. All security vulnerabilities will be promptly addressed.

License

Laravel 2FA is open-sourced software licensed under the MIT License.

Credits

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. 🚀