v2.1.1 · Laravel 11–13 · Nova 5 · MIT

One password is one mistake away.

Passkeys, authenticator apps, email codes and recovery codes for Laravel Nova — with enforcement policy, step-up re-authentication, trusted devices, an audit trail and three administration pages.

$ composer require gabrielesbaiz/nova-two-factor

Verify your identity

00:30

Type six digits — or let it demo itself.

Code from your authenticator appawaiting input
0
Factor types
0
Admin pages
0
Tests passing
0
Remote calls

Factors

Four kinds.
Several per user.

Losing a phone should not mean losing the account. The challenge offers whatever the user actually holds.

Phishing-resistant

Passkeys

WebAuthn credentials stored encrypted:json, looked up by SHA-256 of the credential ID.

Offline

Authenticator apps

160-bit TOTP secrets under an encrypted cast. QR codes generated locally.

No setup

Email codes

HMAC-SHA256 keyed on APP_KEY, single-use, short TTL.

Last resort

Recovery codes

SHA-256 individually, unique index, single-use. Shown once.

Read about the factors →

Screens

Every screen ships
in both themes.

Challenge, enrollment and step-up render outside Nova's shell as server-rendered Blade — a tool-registered Inertia page never resolves on the cold load a challenge always is. Hit the theme switch; these follow it.

ChallengeChallenge
ChallengeWhatever the user holds, with trade-offs shown.
Security cardSecurity card
Security cardWhere a user manages their own factors.
OverviewOverview
Compliance overviewFigures follow the enforcement mode.
Step-upStep-up
Step-upA scoped, signed grant before a dangerous action.
Authenticator enrollmentAuthenticator enrollment
EnrollmentQR generated locally — the secret never leaves your server.
SettingsSettings
SettingsPolicy without a deploy, password-confirmed and audited.
See all 14 screens →

Enforcement

Optional. Encouraged.
Required.

One call sets the policy. Under required, grace runs per account or against one shared deadline for everybody.

ModeBehaviourBlocks?
optionalNothing required, nothing shown.no
encouragedA dismissible prompt. Never blocks a request.never
requiredNova is unreachable until enrolled, once grace expires.yes
// Grace runs per account, or against one shared deadline.
NovaTwoFactor::make()->enforce('required', graceDays: 14);

// Or restrict it to the people who need it.
NovaTwoFactor::make()->requireFor(fn ($user) => $user->hasRole('admin'));
Try the policy simulator →

Administration

Three pages, closed
until you open them.

nova.admin_gate points at an ability no fresh application defines, and an undefined ability is denied. Until you say who may look, nobody can — and the menu entry does not render.

/dashboards/two-factor-compliance

Overview

Are we covered, and who do I chase? Figures follow the enforcement mode, and the tiles filter the queue.

/dashboards/two-factor-settings

Settings

Policy without a deploy. Password-confirmed, audited, with a pause that expires by itself.

/resources/two-factor-audits

Activity

What happened, and who did it? Read-only. Secrets are never recorded.

How oversight works →

Security

What is stored,
and how.

Routes that issue or destroy a factor require a verified session — a cleared challenge, not merely a confirmed password. The attacker this defends against already has the password.

ControlImplementation
TOTP secretsencrypted cast, 160-bit, never in a URL or log
Recovery codesSHA-256, individually, unique index, single-use
Email codesHMAC-SHA256 keyed on APP_KEY, single-use, short TTL
Passkey credentialsencrypted:json; lookup by SHA-256 of the credential ID
Trusted devices64-character token, only its hash stored
Step-up grantsHMAC over session, user, scope and expiry
QR codesGenerated locally. There is no remote code path.
Read the security model →

Installation

Four steps, then
check your work.

Install and publish

Pre-authentication screens render outside Nova's shell, so their assets must reach your public directory.

Add the trait

HasTwoFactorAuthentication on every authenticatable model that may hold a factor.

Register the tool

NovaTwoFactor::make() in NovaServiceProvider::tools().

Run the doctor

It checks what fails silently — unregistered middleware, stale assets, a relying party from the wrong domain.

composer require gabrielesbaiz/nova-two-factor
php artisan vendor:publish --tag=nova-two-factor-assets
php artisan nova-two-factor:doctor
Full installation guide →