bbs-lab / laravel-force-two-factor
Admin-panel-agnostic core for forcing two-factor authentication in any Laravel app: a shared bypass registry (compose several "skip 2FA" reasons) that the nova-force-two-factor and filament-force-two-factor adapters enforce.
Package info
github.com/BBS-Lab/laravel-force-two-factor
pkg:composer/bbs-lab/laravel-force-two-factor
Requires
- php: ^8.2
- illuminate/contracts: ^11.0 || ^12.0 || ^13.0
- illuminate/http: ^11.0 || ^12.0 || ^13.0
- illuminate/support: ^11.0 || ^12.0 || ^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.18
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^9.0 || ^10.0 || ^11.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- pestphp/pest-plugin-mutate: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Admin-panel-agnostic core for forcing two-factor authentication in any Laravel app. It ships the shared bypass registry that lets several independent reasons to skip forced 2FA compose cleanly, and that the adapters enforce:
bbs-lab/nova-force-two-factor— forces Nova's Fortify 2FA.bbs-lab/filament-force-two-factor— plugs into Filament's native multi-factor gate.
You usually install an adapter, which pulls this package in automatically. Install it directly only when you build your own enforcement middleware.
composer require bbs-lab/laravel-force-two-factor
Why a shared registry?
A panel can only wire one "force 2FA" gate, but several packages have a legitimate reason to let a user skip it — e.g. SSO users (their MFA is handled by the identity provider) and users who still owe a forced password rotation (they must change their password first). Each reason registers a callback here; the gate bypasses as soon as any returns true. Nova and Filament read the same registry, so a reason registered once applies to whichever panel enforces 2FA.
Registering a bypass
Callbacks live in code (never in the config file — a Closure cannot be config:cached), so register them in a service provider's boot():
use BBSLab\LaravelForceTwoFactor\Facades\ForceTwoFactor; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Http\Request; ForceTwoFactor::bypass(function (Request $request, Authenticatable $user): bool { return $request->hasSession() && $request->session()->get('okta_authenticated') === true; });
The sibling packages register their own bypass automatically when this package is present:
bbs-lab/laravel-okta— skips forced 2FA for users authenticated via Okta (okta_authenticated).bbs-lab/laravel-password-rotation— skips forced 2FA while a user still owes a forced password rotation, so the rotation happens first.
Configuration
// config/laravel-force-two-factor.php return [ 'enabled' => (bool) env('FORCE_TWO_FACTOR_ENABLED', true), ];
enabled is the master switch shared by every adapter. Publish it with:
php artisan vendor:publish --tag=laravel-force-two-factor-config
Testing
composer test
License
MIT. See LICENSE.md.