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

Google Authenticator Bundle Laravel Package

jonasarts/google-authenticator-bundle

Symfony bundle for adding Google Authenticator two-factor authentication to your app. Provides TOTP secret generation and code validation, with configurable services for integrating 2FA into login flows.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: the package is a Symfony bundle, not a Laravel package. The name says "bundle," the namespace is Jonasarts\GoogleAuthenticatorBundle, and it ships a Bundle class, a DI extension, and a Configuration tree — all of which only resolve inside a Symfony kernel. composer require jonasarts/google-authenticator-bundle in a Laravel app will install the files, but the bundle's main delivery mechanism (service container wiring, compiler passes, bundle config merging) is inert. There is no service provider to auto-register, no facade, no config/google-authenticator.php that Laravel will read.

Where to look first:

  1. The wrapped TOTP class, not the bundle. Open vendor/jonasarts/google-authenticator-bundle/ and follow the service definition to the underlying google-authenticator class (Jonasarts wraps a TOTP library). That class — secret generation, otpauth:// URI construction, verifyCode() — is the only part with value in Laravel. Everything around it is Symfony plumbing.
  2. composer.json, specifically the php, symfony/*, and google-authenticator constraints. A Symfony 4/5-era bundle may not declare PHP 8.2/8.3 support, which turns into a composer resolution conflict before you write a line of code.
  3. DependencyInjection/Configuration.php — this is the real API surface. Config keys for issuer, digits, period, and window live here, and the README is thin, so the source is the contract.

Your first use case should be enrollment, not login enforcement:

// A one-off artisan spike: pull the underlying TOTP class into a throwaway command
$secret = $totp->generateSecret();                        // base32
$uri    = $totp->getUrl('[email protected]', 'MyApp', $secret); // otpauth://...
// verify a code from Google Authenticator / Authy / 1Password
$ok     = $totp->verifyCode($secret, $request->input('code'));

Confirm that loop works end-to-end against a real authenticator app before touching your login flow. If it works, you have a vendorable TOTP implementation. If it doesn't, the ticket is closed and you move on.

The pragmatic recommendation: for a real Laravel 2FA feature, skip the bundle and use pragmarx/google2fa-laravel (Laravel-native, maintained) or spomky-labs/otphp (the maintained OTP core). Use this bundle only if the spike proves something the alternatives lack — unlikely.

Implementation Patterns

Enrollment (per user). The flow is the same regardless of which underlying TOTP library you settle on:

$secret = $totp->generateSecret();
$user->forceFill([
    'totp_secret'  => encrypt($secret),   // never store plaintext
    'totp_enabled' => false,
])->save();

$uri = $totp->getUrl($user->email, config('app.name'), $secret);
// Render $uri as a QR code — bacon/bacon-qr-code or endroid/qr-code.
// This bundle ships no QR renderer; do not assume one exists.

Persist the secret before confirmation so a refresh doesn't orphan it, but keep totp_enabled = false until the user submits a valid code. That confirmation step is what catches mis-scans and client-side clock skew at enrollment, rather than at 3am on their next login.

Enforcement as a middleware, not a form field. Do not add a code input to your existing login form. Keep the TOTP challenge on its own route so session state, rate limiting, and error UX stay independent:

// app/Http/Middleware/RequireTotp.php
public function handle($request, Closure $next)
{
    if (auth()->check() && auth()->user()->totp_enabled
        && ! $request->session()->get('totp_verified')) {
        return redirect()->route('totp.challenge');
    }
    return $next($request);
}

Register it on the web group (or a totp middleware alias applied to authenticated routes). After successful password login, set totp_verified = false and redirect into the challenge; on success, set it true.

Verification belongs in a single service you own, not scattered in controllers:

// app/Services/TotpService.php — thin wrapper you control
public function verify(User $user, string $code): bool
{
    $secret = decrypt($user->totp_secret);
    // window of 1 = accept ±30s
    return $this->totp->verifyCode($secret, $code, 1);
}

Binding this behind an interface (TotpProvider) is the whole point: swap the underlying library later without touching product code. This is the pattern the assessment notes call out explicitly — isolate it, because you are effectively the maintainer.

Backup codes. The bundle does not manage recovery codes, replay protection, or rate limiting. Ship them yourself:

  • Generate 8–10 single-use codes at enrollment, store hashed (Hash::make), show once.
  • Wrap verification in a RateLimiter (RateLimiter::for('totp', fn() => Limit::perMinute(5)->by($user->id))).
  • Reject a code that matches the user's last-verified code within its period (replay protection) — see gotchas.

Integration tip: bypass the bundle entirely. Don't add it to composer.json and hope the Symfony wiring doesn't confuse Composer's autoloader. Vendor the single TOTP class under app/Support/Totp/ and add a test. You get the algorithm without an implied support contract on a 4-star, zero-dependent package.

Gotchas and Tips

The install will "succeed" and do nothing. Laravel's package discovery scans for Illuminate\Support\ServiceProvider implementors in composer.json's extra.laravel.providers. This bundle doesn't provide one. You'll have the files, no container binding, and no error — the most dangerous failure mode for a security feature, because it looks like it's working until you notice nothing is verifying.

PHP version constraints. Verify before any spike. A Symfony 4/5 bundle pinning php: ^7.x will fail composer require on Laravel 10/11 (PHP 8.1+). If it installs, it's usually because someone ran --ignore-platform-reqs — don't ship that.

Clock drift is the #1 production support ticket. Default tolerances vary; the safe setting is a window of 1 (accept the current, previous, and next 30s step). Wider windows reduce lockout tickets but widen the attack window. Monitor the rate of rejected-but-valid attempts — a rising rejection rate is usually drift or a bad QR scan, not an attacker.

Store the secret encrypted, always. encrypt() on write, decrypt() on read. A plaintext totp_secret column in a DB dump is a full 2FA bypass. This is the single most common implementation mistake and the bundle does nothing to prevent it — it hands you a base32 string and trusts you.

Replay is real. TOTP codes are valid for ~30s. Without a "last used code / last used step" column, an attacker who observes a code (shoulder-surf, phishing relay) can reuse it within the window. Store totp_last_used_at (or the counter value) and reject reuse. Verify with hash_equals or the library's constant-time comparison — never ==.

No QR renderer, no recovery flow, no rate limiting. The bundle's description ("helpers for generating secrets, building provisioning URIs, and verifying time-based codes") is accurate and complete. Everything else — QR rendering, backup codes, admin reset, lockout, secret encryption — is your code. Budget accordingly.

Zero community signals mean you own maintenance. Four stars, zero dependents, one maintainer. Every PHP upgrade and Symfony (or TOTP-relevant) CVE becomes your ticket. Acceptable for the algorithm (RFC 6238 is stable), unacceptable for anything around secret storage and provisioning. Pin the version, fork if you vendor, and add your own tests around drift, replay, and constant-time comparison.

Extension points you'll actually want. Wrap the underlying class in app/Services/TotpService and bind an interface in AppServiceProvider. Then your TOTP flow depends on your contract, and swapping jonasarts/... for pragmarx/google2fa (or otphp) becomes a one-file change — which is exactly what you want for a dependency this lightly validated.

Don't pitch this bundle to a reviewer as "the 2FA story." It isn't. It's a TOTP algorithm you could vendor. If the real need is "we need MFA to unblock a security questionnaire," the honest framing is: adopt the Laravel-native package, keep the enrollment/challenge/backup-code pattern above, and treat this bundle only as a reference implementation for the RFC 6238 flow.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core