Install the Package
composer require lunarphp/filament3-2fa
Publish the migration and config:
php artisan vendor:publish --provider="LunarPHP\Filament32FA\Filament32FAServiceProvider" --tag="migrations"
php artisan vendor:publish --provider="LunarPHP\Filament32FA\Filament32FAServiceProvider" --tag="config"
Run the migration:
php artisan migrate
Register the Middleware
Add the Filament32FAMiddleware to your app/Http/Kernel.php under the $middlewareGroups for filament:
'filament' => [
// ...
\LunarPHP\Filament32FA\Middleware\Filament32FAMiddleware::class,
],
Enable 2FA for Users
Use the enableTwoFactorAuthentication() method on a user model:
use LunarPHP\Filament32FA\Traits\HasTwoFactorAuthentication;
class User extends Authenticatable
{
use HasTwoFactorAuthentication;
}
First Use Case: Enable 2FA for a User Trigger the 2FA setup flow via a Filament resource or standalone page:
use LunarPHP\Filament32FA\Pages\SetupTwoFactorAuthentication;
// In a Filament resource action or standalone page
SetupTwoFactorAuthentication::make();
User-Specific 2FA Setup
SetupTwoFactorAuthentication page in a Filament resource’s pages or as a standalone page.public static function getPages(): array
{
return [
'setup-2fa' => Pages\SetupTwoFactorAuthentication::route('/2fa'),
];
}
Conditional 2FA Enforcement Override the middleware to exclude certain routes or users:
public function handle($request, Closure $next)
{
if ($request->user()->isAdmin()) {
return $next($request);
}
return $this->checkTwoFactorAuthentication($request, $next);
}
Passkey Authentication
Leverage the built-in passkey support via the VerifyPasskey page:
use LunarPHP\Filament32FA\Pages\VerifyPasskey;
VerifyPasskey::make();
Customizing Recovery Codes
Extend the RecoveryCode model or modify the config/filament3-2fa.php to adjust:
'recovery_codes' => [
'count' => 10, // Default: 10 recovery codes
'expires_in' => null, // Set to null for no expiry
],
Integrating with Filament Resources Add a 2FA toggle to a user table column:
use LunarPHP\Filament32FA\Columns\TwoFactorAuthenticationColumn;
TwoFactorAuthenticationColumn::make()
->toggleable(isToggleable: true),
Middleware Placement
Filament32FAMiddleware is after auth middleware in Kernel.php. Misplacement can cause infinite redirects.User Model Requirements
HasTwoFactorAuthentication trait. Forgetting this will break 2FA checks.Session Handling
SESSION_DRIVER is set to database or redis in .env for reliability.Rate Limiting
config/filament3-2fa.php:
'throttle' => [
'max_attempts' => 5,
'decay_minutes' => 15,
],
Testing 2FA Flows
fakeTwoFactorAuth() helper in tests to simulate 2FA:
$this->fakeTwoFactorAuth();
$this->actingAs($user)->get('/filament')->assertOk();
APP_DEBUG=true) to inspect 2FA-related errors in storage/logs/laravel.log.two_factor_authentication table exists and contains user records:
php artisan tinker
>> \DB::table('two_factor_authentication')->get();
php artisan optimize:clear
php artisan view:clear
Custom Recovery Code Storage
Override the RecoveryCode model to use a custom storage mechanism (e.g., encrypted storage):
class CustomRecoveryCode extends RecoveryCode
{
protected static function boot()
{
parent::boot();
static::saving(function ($model) {
$model->code = encrypt($model->code);
});
}
}
Event Listeners
Listen for 2FA events (e.g., TwoFactorAuthenticated, TwoFactorEnabled) in EventServiceProvider:
protected $listen = [
\LunarPHP\Filament32FA\Events\TwoFactorEnabled::class => [
\App\Listeners\LogTwoFactorEnable::class,
],
];
Custom Notifications
Extend the TwoFactorNotification class to send custom emails/SMS:
use LunarPHP\Filament32FA\Notifications\TwoFactorNotification as BaseNotification;
class CustomTwoFactorNotification extends BaseNotification
{
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Your 2FA Code')
->line('Your code: ' . $this->code);
}
}
Update the config to use your class:
'notifications' => [
'class' => \App\Notifications\CustomTwoFactorNotification::class,
],
Passkey Customization
Override the passkey verification logic by extending VerifyPasskey:
class CustomVerifyPasskey extends VerifyPasskey
{
protected function verifyPasskey($request)
{
// Custom logic here
return $this->authenticate($request);
}
}
How can I help you explore Laravel packages today?