Weave Code
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

2Fa Bundle Laravel Package

scheb/2fa-bundle

Symfony bundle providing a generic framework for adding two-factor authentication (2FA) to your app. Integrates with Symfony Security and supports multiple 2FA methods via a consistent interface, with full docs on symfony.com.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use Case

  1. Installation:

    • Requires Symfony, but for Laravel, start by cloning the core logic from scheb/2fa and adapting it.
    • Install dependencies:
      composer require spomky-labs/otphp  # For TOTP/HOTP logic (used by scheb/2fa)
      composer require endroid/qr-code      # For QR code generation
      
  2. Database Setup:

    • Create a migration for 2FA secrets (adapted from Symfony’s schema):
      php artisan make:migration create_two_factor_secrets_table
      
    • Define the table structure:
      Schema::create('two_factor_secrets', function (Blueprint $table) {
          $table->id();
          $table->foreignId('user_id')->constrained()->onDelete('cascade');
          $table->string('secret')->unique();
          $table->string('algorithm')->default('sha1');
          $table->string('digits')->default('6');
          $table->string('period')->nullable();
          $table->timestamps();
      });
      
  3. Basic Middleware:

    • Create middleware to check 2FA status:
      php artisan make:middleware CheckTwoFactor
      
    • Implement logic to verify TOTP (example using spomky-labs/otphp):
      public function handle($request, Closure $next)
      {
          if (auth()->check() && auth()->user()->mustVerifyTwoFactor()) {
              $totp = new TOTP($request->input('two_factor_secret'));
              if (!$totp->verify($request->input('two_factor_code'))) {
                  return redirect()->back()->withErrors(['2fa' => 'Invalid code.']);
              }
          }
          return $next($request);
      }
      
  4. First Use Case:

    • Protect a route (e.g., /dashboard) with the middleware:
      Route::middleware(['auth', 'check.two.factor'])->group(function () {
          Route::get('/dashboard', [DashboardController::class, 'index']);
      });
      
    • Add a route for enabling 2FA:
      Route::get('/enable-2fa', [TwoFactorController::class, 'showSetupForm']);
      Route::post('/enable-2fa', [TwoFactorController::class, 'storeSetup']);
      
  5. User Setup Flow:

    • Generate a secret and QR code in the controller:
      public function showSetupForm()
      {
          $secret = $this->generateSecret();
          $qrCodeUrl = $this->generateQrCodeUrl($secret);
          return view('two-factor.setup', compact('secret', 'qrCodeUrl'));
      }
      
    • Store the secret and redirect to verification:
      public function storeSetup(Request $request)
      {
          $user = auth()->user();
          $user->twoFactorSecret()->create([
              'secret' => $request->input('secret'),
              'algorithm' => 'sha1',
              'digits' => '6',
          ]);
          return redirect()->route('verify.2fa');
      }
      
  6. Verify Setup:

    • Add a route to verify the user’s TOTP code:
      Route::get('/verify-2fa', [TwoFactorController::class, 'showVerificationForm']);
      Route::post('/verify-2fa', [TwoFactorController::class, 'verifySetup']);
      

Implementation Patterns

Usage Patterns

  1. Modular Middleware:

    • Use middleware for granular control over 2FA checks:
      • CheckTwoFactor: Validates TOTP on protected routes.
      • VerifyTwoFactorSetup: Ensures 2FA is enabled before allowing access.
    • Example middleware stack:
      Route::middleware(['auth', 'verified', 'check.two.factor'])->group(...);
      
  2. Service-Based Logic:

    • Encapsulate 2FA logic in a service (e.g., TwoFactorService):
      class TwoFactorService {
          public function generateSecret(): string
          {
              return bin2hex(random_bytes(20));
          }
      
          public function generateQrCodeUrl(string $secret, string $issuer = 'YourApp'): string
          {
              return 'otpauth://totp/' . urlencode($issuer) . ':' . urlencode(auth()->user()->email) . '?secret=' . urlencode($secret) . '&issuer=' . urlencode($issuer);
          }
      
          public function verifyCode(string $secret, string $code, int $digits = 6): bool
          {
              $totp = new TOTP($secret);
              return $totp->verify($code, $digits);
          }
      }
      
  3. Event-Driven Workflows:

    • Use Laravel events for 2FA lifecycle:
      • TwoFactorEnabled: Triggered when a user enables 2FA.
      • TwoFactorVerificationFailed: Log failed attempts.
    • Example:
      class TwoFactorService {
          public function enableTwoFactor(User $user, string $secret)
          {
              $user->twoFactorSecret()->create([
                  'secret' => $secret,
                  'algorithm' => 'sha1',
              ]);
              event(new TwoFactorEnabled($user));
          }
      }
      
  4. Backup Codes:

    • Generate and store backup codes securely:
      public function generateBackupCodes(int $count = 10): array
      {
          $codes = [];
          for ($i = 0; $i < $count; $i++) {
              $codes[] = bin2hex(random_bytes(3));
          }
          return $codes;
      }
      
    • Store hashed codes in the database:
      $user->twoFactorBackupCodes()->createMany(
          array_map(fn ($code) => ['code' => hash('sha256', $code)], $backupCodes)
      );
      
  5. Recovery Flow:

    • Implement a recovery route for lost devices:
      Route::post('/recover-2fa', [TwoFactorController::class, 'recover'])->name('recover.2fa');
      
    • Validate backup codes or send a recovery link (if using email/SMS).

Workflows

  1. User Enrollment:

    • Step 1: User requests 2FA setup (/enable-2fa).
    • Step 2: System generates a secret and QR code.
    • Step 3: User scans QR code in an authenticator app (e.g., Google Authenticator).
    • Step 4: User submits a test code to verify setup.
    • Step 5: Backup codes are generated and displayed.
  2. Login Flow:

    • Step 1: User logs in with credentials.
    • Step 2: System checks if 2FA is enabled.
    • Step 3: If enabled, prompt for TOTP code.
    • Step 4: Validate code; grant access if valid.
  3. Recovery Flow:

    • Step 1: User requests recovery (/recover-2fa).
    • Step 2: System prompts for backup code or sends recovery email.
    • Step 3: User submits recovery code/email code.
    • Step 4: System disables 2FA temporarily or allows re-enrollment.

Integration Tips

  1. Laravel Auth Integration:

    • Extend the User model to track 2FA status:
      class User extends Authenticatable {
          public function mustVerifyTwoFactor(): bool
          {
              return $this->twoFactorSecret()->exists();
          }
      }
      
  2. Session Binding:

    • Bind the user’s session to their 2FA device to prevent session hijacking:
      public function handle($request, Closure $next)
      {
          $response = $next($request);
          if ($response->isRedirect() && auth()->check() && auth()->user()->mustVerifyTwoFactor()) {
              $response->headers->set('X-TwoFactor-Bound', 'true');
          }
          return $response;
      }
      
  3. Rate Limiting:

    • Protect against brute-force attacks on 2FA codes:
      Route::middleware(['throttle:5,1'])->post('/verify-2fa', ...);
      
  4. Testing:

    • Use spomky-labs/otphp to mock TOTP verification in tests:
      $totp = Mockery::mock(TOTP::class);
      $totp->shouldReceive('verify')->andReturn(true);
      $this->app->instance(TOTP::class, $totp);
      
  5. Artisan Commands:

    • Add commands for common 2FA tasks:
      php artisan make:command GenerateBackupCodes
      
      class GenerateBackupCodes extends Command {
          protected $signature = 'two-factor:backup-codes {user?}';
          public function handle()
          {
      
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.
bugban/symfony
beyonder-capi/workflow-extensions-bundle
beyonder-capi/job-queue-bundle
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin