elgibor-solution / laravel-2fa
Two-Factor Authentication package for Laravel supporting Google Authenticator (TOTP) and self-generated codes via SMS/WhatsApp/Email.
Requires
- php: >=8.1
- ext-json: *
- illuminate/mail: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
This package is not auto-updated.
Last update: 2025-08-26 00:43:03 UTC
README
Two-Factor Authentication package for Laravel that supports:
- Google Authenticator (TOTP)
- Self-generated one-time codes with configurable expiry
- Delivery via Email (built-in), SMS, or WhatsApp (user-provided callbacks)
- Built-in fraud protection: attempt limits, cooldowns, per-user lock
Requirements
- PHP 8.1+
- Laravel 10 or 11
Installation
composer require elgibor-solution/laravel-2fa
Publish config and (optionally) migrations:
php artisan vendor:publish --provider="ESolution\Laravel2FA\Laravel2FAServiceProvider" --tag=2fa-config php artisan vendor:publish --provider="ESolution\Laravel2FA\Laravel2FAServiceProvider" --tag=2fa-migrations php artisan migrate
Configuration
config/2fa.php
channels.email/sms/whatsapp
— enable built-in email sender; provide SMS/WhatsApp callbacks.self_generated_ttl
— expiry (seconds) for self-generated codes.code_length
— digits for self-generated codes.max_attempts
,lock_minutes_after_max
— fraud control.cooldown_seconds_between_requests
— min time between code requests.totp_drift
— allowed time drift for TOTP.issuer
— shown in Google Authenticator.tables
— override table names if needed.
Binding SMS / WhatsApp senders
In AppServiceProvider@boot()
or any service provider:
use Illuminate\Support\Facades\App; // SMS App::singleton('2fa.sender.sms', function () { return function (string $to, string $message, array $context = []) { // Integrate your SMS gateway here // Example: Sms::to($to)->send($message); }; }); // WhatsApp App::singleton('2fa.sender.whatsapp', function () { return function (string $to, string $message, array $context = []) { // Integrate your WhatsApp provider here // Example: WhatsApp::sendText($to, $message); }; });
Email is supported out of the box via Mail::raw()
.
Routes
These routes are auto-registered under /2fa
with web,auth
middleware.
POST /2fa/init-totp
→ Start TOTP setup. Returns{ secret, otpauth_uri }
.POST /2fa/confirm-totp
→ Enable TOTP (body:code
).POST /2fa/disable
→ Disable 2FA for the authenticated user.POST /2fa/create
→ Generate self code and send (body:channel, destination, purpose?
).POST /2fa/validate
→ Validate any code (body:code, purpose?
).
Using the Facade
use TwoFA; // Start TOTP enrollment $resp = TwoFA::initTotp($user->id); // ['secret' => '...', 'otpauth_uri' => '...'] // Confirm and enable TOTP $ok = TwoFA::confirmTotp($user->id, $request->code); // Disable 2FA TwoFA::disable($user->id); // Create a self-generated code and deliver it $res = TwoFA::createSelfGenerated($user->id, 'sms', $user->phone, 'login'); // Validate a code (works for TOTP or self-generated depending on user settings) $isValid = TwoFA::validate($user->id, $request->code, 'login');
Generating a QR Code for Google Authenticator
initTotp()
returns an otpauth://
URI. Render a QR code on your frontend using any QR library (e.g., JavaScript QR libraries). Users can scan that QR with Google Authenticator.
Fraud & Security
- Hashed codes at rest (HMAC-SHA256 with
APP_KEY
). Sethash_codes=false
to store plaintext (not recommended). - Per-code attempt limit (config
max_attempts
). - Cooldown between requests (
cooldown_seconds_between_requests
). - Temporary account lock after too many failures (
lock_minutes_after_max
). Lock status is tracked intwo_fa_settings.locked_until
. - IP & User-Agent logging for every action in
two_fa_logs
.
Tip: Add additional monitoring or alerts by listening to model events or querying
two_fa_logs
.
Middleware
An optional middleware ESolution\Laravel2FA\Http\Middleware\Enforce2FA
is included. It blocks requests if the account is currently locked. Register it in app/Http/Kernel.php
and apply where needed.
protected $routeMiddleware = [ // ... 'enforce2fa' => \ESolution\Laravel2FA\Http\Middleware\Enforce2FA::class, ];
Database
two_fa_settings
: per-user status, method (totp
orself
), secret, lock.two_fa_codes
: self-generated codes, expiry, attempts, delivery channel.two_fa_logs
: audit log of events.
Testing Locally
- Enable mail logging (e.g.,
MAIL_MAILER=log
) to see email messages in logs. - For SMS/WhatsApp, just bind callbacks that
Log::info()
the outbound text.
License
Apache-2.0