Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Google2Fa Laravel Package

oluomotoso/nova-google2fa

Add Google Two-Factor Authentication to Laravel Nova. This package brings TOTP-based 2FA to your Nova login flow, letting users enroll with an authenticator app via QR code and confirm a one-time code at sign-in for stronger account security.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the fork directly (it will not resolve via the parent package name):
    composer require oluomotoso/nova-google2fa
    
  2. Publish config and migrations, then migrate:
    php artisan vendor:publish --provider="Olumotoso\NovaGoogle2FA\Google2FAServiceProvider"
    php artisan migrate
    
  3. Register the tool (or card) in app/Providers/NovaServiceProvider.php inside tools():
    public function tools()
    {
        return [
            new \Olumotoso\NovaGoogle2FA\Google2FA,
        ];
    }
    
  4. Clear Nova's cached assets (php artisan nova:publish and php artisan optimize:clear) and hard-refresh the Nova UI so the new tool appears in the sidebar.

Where to look first:

  • config/google2fa.php — window tolerance, issuer name, secret column/table, recovery-code toggle.
  • The published migration — confirm whether the secret lands on users or a dedicated table; this shapes the rest of your integration.
  • The package's middleware — that's where the enforcement decision ("has the user enrolled? has the user verified this session?") actually lives.

First use case: require Google Authenticator for every Nova admin. Assign the tool to a test user, enroll via QR, log out, log back in, and confirm the challenge appears before the dashboard. Do this on a staging deploy before touching production users.

Implementation Patterns

Enrollment-then-enforcement middleware. The typical shape is a middleware that (a) lets the user through if they have no secret and are on the setup tool, (b) redirects enrolled-but-unverified users to the challenge screen, and (c) blocks everyone else from Nova routes until the session flag is set. Register it in config/nova.php (or Nova::middleware([...]) in NovaServiceProvider::booted()), after Nova's own Authenticate middleware so you always have a resolved user.

Secret storage via trait/column. If the package ships a trait, apply it to App\Models\User and cast the secret column as encrypted. Wrap the accessor so anything reading the column gets plaintext, but the DB row is ciphertext. If you're on a dedicated google2fa_secrets table, key the relation off user_id and delete the row on disable so re-enrollment starts clean.

Setup flow as a Nova tool. The tool page renders the QR (via bacon/bacon-qr-code through pragmarx/google2fa), shows the plaintext secret as a fallback, and asks for a 6-digit code to confirm before persisting. Do not persist the secret until confirmation succeeds — otherwise a user who abandons setup gets locked out by your own middleware.

Session verification flag. After a successful code check, the middleware should set a session key (e.g. nova_2fa_verified_at) scoped to the user ID. Bind it to the user so a logout/login cycle re-challenges, and so a session hijack on a shared machine doesn't inherit 2FA state.

Recovery codes. Generate them at enrollment, hash them before storage, show plaintext exactly once, and consume-on-use. This is your only reliable escape hatch short of a DB update.

Testing. Freeze time and generate a valid code in feature tests:

Carbon::setTestNow('2024-01-01 12:00:00');
$code = Google2FA::getCurrentOtp($user->google2fa_secret);
$this->actingAs($user)->post('/nova/2fa/verify', ['code' => $code]);

Also test the "wrong code" and "expired code" paths — those are where middleware ordering bugs surface.

Reusing the primitive outside Nova. If you have a customer-facing app on the same users table, use pragmarx/google2fa (or google2fa-laravel) directly with the same secret column rather than trying to import the Nova middleware. Keep the two enforcement layers in sync through a shared trait or policy.

Gotchas and Tips

  • This is a 0-star fork of carloscgo/nova-google2fa. Bug fixes and Nova API changes land upstream first. Pin a specific commit in composer.json and subscribe to the parent repo's issues; a dev-main reference here is a production liability. If the fork goes stale, be prepared to vendor the diff yourself — it's usually a handful of Nova 4 class/interface updates.
  • Nova 4 asset compilation. Nova 4's tool registration is stricter than Nova 3 (public function boot(), public function render(), menu registration via Menu). If the tool renders blank, run php artisan nova:publish --force and inspect the compiled JS in public/vendor/nova — stale assets are the most common "it installed but does nothing" failure.
  • Don't lock out your only admin. Create a break-glass path before you enable enforcement globally: a console command that clears a user's secret, or an env flag (NOVA_2FA_ENFORCE=false) that the middleware checks. You will need it during a bad deploy.
  • Clock skew. pragmarx/google2fa accepts a window of 0 by default. Set window => 1 (or 2) in config so codes from slightly-off phone clocks still pass. Don't go higher than 2 — you're trading security for user support tickets.
  • Middleware ordering. If your 2FA middleware runs before Nova's Authenticate, $request->user() is null and the middleware silently no-ops or 500s. Verify it appears after Nova's auth stack in the resolved middleware list (php artisan route:list -v on a Nova route).
  • API bypass. The middleware protects Nova web routes only. If you expose the same users through Sanctum or Passport, those tokens bypass 2FA entirely. Decide explicitly whether that's acceptable.
  • Secret leakage in logs. Nova's debug toolbar and Laravel's query log will happily print the plaintext secret if you forget the encrypted cast. Add the column to $hidden on the model and scrub it from any request-logging middleware.
  • Upgrade migrations. Published migrations are copied, not referenced, so a package update that adds a column won't touch your existing table. Watch the repo's changelog and re-publish if the schema changes.
  • Recovery-code regen wipes the old set. Make the "regenerate" action require a current code, or a stolen session can invalidate the legitimate user's backups.
  • Extension point to prefer: rather than editing vendor files to tweak the enforcement rules, bind a custom middleware class that extends the package's and override the handle() decision. That keeps the fork replaceable if a maintained alternative appears.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource