liberusoftware/two-factor-authentication-livewire
A Laravel Livewire package for adding two-factor authentication to your app. It provides components for enabling 2FA, verifying authentication codes, and managing recovery codes, helping secure user accounts with a straightforward setup.
This package is a presentation adapter: it ships Livewire components that wrap an underlying two-factor authentication service (Fortify-style or a liberusoftware/module-two-factor-authentication core). Treat it as the UI layer — the enable/disable/verify logic lives elsewhere. That distinction shapes everything below.
Minimal steps:
composer require liberusoftware/two-factor-authentication-livewire
php artisan vendor:publish --provider="LiberuSoftware\TwoFactorAuthenticationLivewire\TwoFactorAuthenticationServiceProvider" — namespace may differ; run vendor:publish interactively to confirm tags).TwoFactorAuthenticatable) and that the two_factor_* columns/migration exist — usually supplied by the core module, not this one./user/two-factor-authentication settings page rendering the enable component, and a middleware-protected challenge component rendered after password login for users with 2FA confirmed.First thing to verify: read src/Livewire/ and routes/ — that tells you exactly which component aliases (<livewire:two-factor-authentication.enable /> etc.) and routes (typically /user/two-factor-qr-code, /user/two-factor-recovery-codes, /user/confirm-password) are registered. These are almost always Fortify-compatible endpoint names.
Settings page (enable/disable + recovery codes). Render the enable component conditionally on $user->two_factor_secret:
@if ($user->two_factor_secret && ! $user->two_factor_confirmed_at)
<livewire:two-factor-authentication.confirm />
@elseif ($user->two_factor_confirmed_at)
<livewire:two-factor-authentication.recovery-codes />
<livewire:two-factor-authentication.disable />
@else
<livewire:two-factor-authentication.enable />
@endif
Login challenge. After Auth::attempt(), redirect users with a confirmed secret to a challenge route rather than the dashboard:
if ($user->two_factor_confirmed_at) {
session(['2fa.user_id' => $user->id]);
return redirect()->route('two-factor.challenge');
}
The challenge component reads the pending user from session, verifies the TOTP or recovery code via the core module, then calls Auth::loginUsingId() and session()->forget('2fa.user_id').
Recovery code rotation. Recovery codes are typically regenerated via a POST to /user/two-factor-recovery-codes — wire a wire:click button to that endpoint (usually with wire:confirm to prevent accidental regeneration, since it invalidates old codes).
Disable gating. Pair the disable component with password.confirm middleware — 2FA should never be turned off from a hijacked session without re-entering the password.
Composition with Breeze/Jetstream. These packages assume Fortify's underlying routes. If you're not using Fortify, either install it alongside so the endpoints exist, or stub the three JSON endpoints (qr-code, recovery-codes GET/POST, secret-key) in your own controller — the Livewire components just fetch() them.
two-factor-authentication module (or Fortify). Components render but TwoFactorAuthentication::enable() calls explode with "class not found" or a 419/404 on the fetch endpoints. Always confirm the core is present and its migration has run.two_factor_confirmed_at vs two_factor_secret. Enable state, confirmation state, and "has recovery codes" are three separate flags. Rendering the wrong component for a half-enabled user (secret set, not confirmed) leaves them in limbo — they can't log in and can't regenerate codes. Handle the unconfirmed branch explicitly.2fa.user_id or login.id). If you use a custom login flow, mirror that key or override the component — the package won't tell you which key it wants until you read the source.auth + CSRF. If you mount the enable component outside the authenticated area (e.g. during registration), those fetches return 401/419 silently — check the browser network tab before debugging the component.two_factor_secret is only populated on first enable; hitting "enable" twice without the disable step can rotate the secret underneath an already-scanned QR, locking users out. Guard the enable action on the server.recovery-codes component typically re-fetches from the server every render, meaning codes are visible in the DOM to anyone with the session. Do not cache or Livewire-snapshot the codes — the core module usually stores them encrypted and returns plaintext only on demand.must_enable flag on the user model. The adapter is thin by design.NOASSERTION license means: pin the version in composer.json, vendor the components into your app if you need to patch them, and expect namespace/route drift between minor versions. Write a smoke test (enable → confirm → login → recover → disable) so upgrades fail loudly rather than at the login screen.wire:model errors on the challenge form usually trace back to the core module's exception on an expired TOTP window — surface those as validation errors, not 500s, or users will see blank screens on stale codes.How can I help you explore Laravel packages today?