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

S4 2Fa Laravel Package

dracoder/s4-2fa

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require dracoder/s4-2fa
    

    (Note: The package is designed for Symfony, but Laravel users can adapt it via a wrapper or standalone usage.)

  2. Basic Usage

    • Initialize the 2FA provider:
      use Dracoder\S4TwoFactor\TwoFactorAuth;
      
      $twoFactor = new TwoFactorAuth();
      $secret = $twoFactor->generateSecret(); // Generates a Base32 secret
      
    • Generate a QR code (use a library like chillerlan/qr-code for Laravel):
      $qrCodeUrl = $twoFactor->getQRCodeUrl('issuer', '[email protected]', $secret);
      
    • Verify a TOTP code:
      $isValid = $twoFactor->verifyCode($secret, '123456');
      
  3. First Use Case

    • Store the $secret in the user model (e.g., user_2fa_secret column).
    • Display the QR code to the user during 2FA setup.
    • Prompt for a code and verify it before enabling 2FA.

Implementation Patterns

Workflow: Enabling 2FA

  1. User Initiates Setup

    • Trigger a controller action to generate a secret and QR code.
    • Store the secret in the database (encrypted if sensitive).
  2. Code Verification

    • After scanning the QR, prompt the user for a test code.
    • Verify with:
      if ($twoFactor->verifyCode($secret, $userInput)) {
          $user->enableTwoFactor(); // Custom logic to mark user as 2FA-enabled
      }
      
  3. Login Flow

    • After password auth, check for 2FA:
      if ($user->isTwoFactorEnabled()) {
          $code = request('two_factor_code');
          if (!$twoFactor->verifyCode($user->twoFactorSecret, $code)) {
              return back()->withErrors(['2fa' => 'Invalid code']);
          }
      }
      

Integration Tips

  • Database Storage Use Laravel’s encrypt() for the secret:

    $user->two_factor_secret = encrypt($secret);
    $user->save();
    

    Retrieve with decrypt($user->two_factor_secret).

  • Caching TOTP Codes The package uses a 30-second window for validation. Cache verification results briefly to avoid rate-limiting:

    Cache::put("2fa_{$user->id}", true, now()->addSeconds(30));
    
  • Fallback Recovery Store backup codes (manually generated) in user_backup_codes (JSON-encoded array). Clear after use.

  • Middleware Create a VerifyTwoFactor middleware to protect routes:

    public function handle($request, Closure $next) {
        if ($request->user()->isTwoFactorEnabled() && !$request->session()->has('2fa_verified')) {
            return redirect()->route('2fa.verify');
        }
        return $next($request);
    }
    

Gotchas and Tips

Pitfalls

  1. Time Synchronization

    • TOTP codes rely on server time. Use Carbon or DateTime consistently:
      $twoFactor->setTimeSource(function() {
          return Carbon::now()->getTimestamp();
      });
      
    • For testing, mock the time source to avoid flaky assertions.
  2. Secret Length

    • Ensure the secret is 32 bytes (Base32 encoded). Shorter secrets may fail validation:
      if (strlen($secret) !== 32) {
          throw new \InvalidArgumentException('Secret must be 32 characters (Base32)');
      }
      
  3. Rate Limiting

    • Aggressive retries on invalid codes may lock users out. Implement a temporary lockout (e.g., 5 failed attempts → 5-minute cooldown).
  4. Database Migrations

    • Add columns for:
      $table->string('two_factor_secret')->nullable();
      $table->json('backup_codes')->nullable();
      $table->boolean('two_factor_enabled')->default(false);
      

Debugging

  • Invalid Codes

    • Check if the secret is correctly decrypted.
    • Verify the time window (default: 30s). Use:
      $twoFactor->verifyCode($secret, $code, 1); // Allow 1 step (15s) for testing.
      
    • Log the expected code for comparison:
      $expectedCode = $twoFactor->getCurrentCode($secret);
      logger("Expected: {$expectedCode}, Got: {$userInput}");
      
  • QR Code Issues

    • Ensure the issuer name and email are URL-encoded:
      $qrCodeUrl = $twoFactor->getQRCodeUrl(
          urlencode('MyApp'),
          urlencode('[email protected]'),
          $secret
      );
      

Extension Points

  1. Custom Algorithms Override the default TOTP algorithm (SHA1) by extending the TwoFactorAuth class:

    class CustomTwoFactorAuth extends TwoFactorAuth {
        protected function getHashAlgorithm() {
            return 'sha256';
        }
    }
    
  2. Event Dispatching Trigger events for 2FA actions (e.g., TwoFactorEnabled, BackupCodeUsed):

    event(new TwoFactorEnabled($user));
    
  3. Multi-Factor Support Combine with other auth methods (e.g., hardware keys) by extending the verification logic:

    public function verifyMultiFactor($secret, $code, $hardwareKey) {
        return $this->verifyCode($secret, $code) && $this->validateHardware($hardwareKey);
    }
    
  4. Laravel Service Provider Bind the package to the container for dependency injection:

    $this->app->singleton(TwoFactorAuth::class, function() {
        $twoFactor = new TwoFactorAuth();
        $twoFactor->setTimeSource(fn() => Carbon::now()->getTimestamp());
        return $twoFactor;
    });
    
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.
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen