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

Recovery Laravel Package

pragmarx/recovery

Generate customizable recovery/backup codes for 2FA account recovery. Create arrays, JSON, or (Laravel) Collections, and tune how many codes to make plus blocks and characters per block for your preferred format and length.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require pragmarx/recovery
    

    Add to config/auth.php under guards (if using Laravel's auth):

    'web' => [
        'driver' => 'session',
        'provider' => 'users',
        'recovery' => true, // Enable recovery codes
    ],
    
  2. Publish Config

    php artisan vendor:publish --provider="Pragmarx\Recovery\RecoveryServiceProvider"
    

    Configure config/recovery.php (default: 10 codes, 6 digits, 30-day expiry).

  3. First Use Case: Generate Codes

    use Pragmarx\Recovery\Recovery;
    
    $user = auth()->user();
    $codes = Recovery::generate($user); // Returns array of codes
    

    Store the hashed codes in user.recovery_codes (migration provided in package).


Key Files to Review

  • Migrations: database/migrations/xxxx_create_recovery_codes_table.php
  • Service Provider: vendor/pragmarx/recovery/src/RecoveryServiceProvider.php
  • Recovery Facade: vendor/pragmarx/recovery/src/Facades/Recovery.php
  • Config: config/recovery.php

Implementation Patterns

Workflow: User Recovery Flow

  1. Generate Codes (Admin/Onboarding)

    $codes = Recovery::generate($user);
    // Send via email/SMS (e.g., using Laravel Notifications)
    
  2. Validate Codes (Login/2FA Fallback)

    if (Recovery::attempt($user, $input['code'])) {
        auth()->login($user, true); // Auto-login on success
    }
    
  3. Rotate Codes (Security)

    Recovery::rotate($user); // Invalidates all existing codes
    

Integration with Laravel Auth

  • Middleware: Use auth:web guard with recovery enabled.
  • Login Controller:
    public function login(Request $request) {
        $credentials = $request->only(['email', 'password']);
        if (!auth()->attempt($credentials)) {
            return back()->withErrors(['email' => 'Invalid credentials']);
        }
        // Check for 2FA (e.g., using `laravel-2fa`)
        if (auth()->user()->has2faEnabled()) {
            return redirect()->route('verify.2fa');
        }
        // Fallback to recovery codes
        return view('auth.recovery');
    }
    

Extending Functionality

  • Custom Storage: Override Pragmarx\Recovery\Recovery::storeCodes() to use a different DB table or cache.
  • Code Format: Modify config/recovery.php to change length/digits:
    'code' => [
        'length' => 8,
        'digits' => true,
    ],
    
  • Events: Listen for recovery.codes.generated or recovery.code.attempted:
    Recovery::generate($user)->each(fn($code) => event(new CodeGenerated($user, $code)));
    

Gotchas and Tips

Pitfalls

  1. Code Expiry

    • Default expiry is 30 days. Reset via Recovery::rotate($user) or update config/recovery.php:
      'expiry' => 90, // Days
      
    • Debug Tip: Check user.recovery_codes table for expires_at timestamps.
  2. Rate Limiting

    • No built-in rate limiting. Add middleware:
      use Illuminate\Cache\RateLimiting\Limit;
      
      RateLimiter::for('recovery_attempts', function (Request $request) {
          return Limit::perMinute(5)->by($request->ip());
      });
      
  3. Code Reuse

    • Codes are single-use by default. To allow reuse, modify Pragmarx\Recovery\Recovery::attempt():
      $code = RecoveryCode::where('code', $code)
          ->where('user_id', $user->id)
          ->whereNull('used_at')
          ->first();
      

Debugging

  1. Check Generated Codes

    dd(Recovery::getCodes($user)); // Returns unhashed codes (for testing)
    
  2. Verify Hashing

    • Codes are hashed with hash_hmac(). Override in config/recovery.php:
      'hash_algorithm' => 'sha256',
      
  3. Log Attempts

    • Enable query logging in .env:
      DB_LOG_QUERIES=true
      
    • Check user.recovery_attempts table for failed attempts.

Configuration Quirks

  • Guard-Specific Codes
    • Codes are tied to the guard name (e.g., web). Use Recovery::guard('api')->generate($user) for multi-guard setups.
  • Custom User Model
    • Ensure your User model has recoveryCodes() relationship:
      public function recoveryCodes() {
          return $this->hasMany(RecoveryCode::class);
      }
      

Extension Points

  1. Custom Code Generator

    • Override Pragmarx\Recovery\Generators\CodeGenerator:
      class CustomGenerator extends CodeGenerator {
          public function generate(): string {
              return Str::random(8); // Custom logic
          }
      }
      
    • Bind in AppServiceProvider:
      Recovery::setGenerator(new CustomGenerator());
      
  2. Multi-Factor Recovery

    • Combine with laravel-2fa:
      if (TwoFactor::verifyCode($user, $input['code'])) {
          // Success
      } elseif (Recovery::attempt($user, $input['recovery_code'])) {
          // Fallback
      }
      
  3. Audit Logging

    • Extend Pragmarx\Recovery\RecoveryCode model to log events:
      protected static function boot() {
          parent::boot();
          static::created(fn($code) => Log::info("Recovery code generated for {$code->user->email}"));
      }
      
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4
php-http/client-implementation
phpcr/phpcr-implementation
cucumber/gherkin-monorepo
haydenpierce/class-finder
psr/simple-cache-implementation
uri-template/tests