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

Laravel User Security Laravel Package

raditzfarhan/laravel-user-security

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require raditzfarhan/laravel-user-security:^1.0
    

    For Laravel ≥5.5, auto-discovery handles the service provider registration. For older versions or Lumen, manually register RaditzFarhan\UserSecurity\UserSecurityServiceProvider in config/app.php or bootstrap/app.php.

  2. Publish Config Publish the default config to customize security settings:

    php artisan vendor:publish --provider="RaditzFarhan\UserSecurity\UserSecurityServiceProvider" --tag="config"
    

    Modify config/user-security.php to adjust:

    • pin_length (default: 6)
    • mnemonic_length (default: 12)
    • two_factor_enabled (default: false)
  3. Extend User Model Add the HasSecurity trait to your User model:

    use RaditzFarhan\UserSecurity\Traits\HasSecurity;
    
    class User extends Authenticatable
    {
        use HasSecurity;
        // ...
    }
    

    Run migrations:

    php artisan migrate
    
  4. First Use Case: Enforcing a Security PIN

    // Set a PIN for a user
    $user->setSecurityPin('123456');
    
    // Verify PIN during login
    if (RFAuthenticator::verifyPin($user, '123456')) {
        // Proceed with authentication
    }
    

Implementation Patterns

Core Workflows

1. Security PIN Integration

  • Registration Flow:
    // Generate and store a PIN (auto-generated or user-provided)
    $pin = RFAuthenticator::generatePin(); // Default: 6-digit
    $user->setSecurityPin($pin);
    
  • Login Validation:
    // Middleware example: `app/Http/Middleware/CheckPin.php`
    public function handle($request, Closure $next)
    {
        $user = auth()->user();
        if (!$user->hasSecurityPin() || !RFAuthenticator::verifyPin($user, $request->pin)) {
            return redirect()->back()->withErrors(['pin' => 'Invalid PIN']);
        }
        return $next($request);
    }
    
  • Forgot PIN:
    // Reset via email (extend with Laravel Notifications)
    $user->resetSecurityPin();
    

2. Mnemonic Key for Recovery

  • Generate/Store:
    $mnemonic = RFAuthenticator::generateMnemonic(); // Default: 12-word phrase
    $user->setMnemonicKey($mnemonic);
    
  • Recovery Flow:
    if (RFAuthenticator::verifyMnemonic($user, $request->mnemonic)) {
        // Unlock account or reset PIN
    }
    
  • Display to User:
    // Show mnemonic in a secure modal (e.g., during registration)
    <div class="mnemonic-display">{{ $user->mnemonic_key }}</div>
    

3. Two-Factor Authentication (2FA)

  • Enable 2FA:
    $user->enableTwoFactorAuth();
    
  • Generate TOTP Secret:
    $secret = RFAuthenticator::generateTwoFactorSecret();
    $user->setTwoFactorSecret($secret);
    
  • Verify TOTP:
    use RaditzFarhan\UserSecurity\Facades\RFAuthenticator;
    
    if (RFAuthenticator::verifyTwoFactorCode($user, $request->code)) {
        // Authenticate
    }
    
  • QR Code Generation (use qrlink package):
    $qrCodeUrl = RFAuthenticator::getTwoFactorQRCodeUrl($user);
    

4. Middleware Integration

  • Protect Routes:
    Route::middleware(['auth', 'pin'])->group(function () {
        // Routes requiring PIN
    });
    
    Register middleware in app/Http/Kernel.php:
    protected $routeMiddleware = [
        'pin' => \RaditzFarhan\UserSecurity\Http\Middleware\CheckPin::class,
        'mnemonic' => \RaditzFarhan\UserSecurity\Http\Middleware\CheckMnemonic::class,
        'twofactor' => \RaditzFarhan\UserSecurity\Http\Middleware\CheckTwoFactor::class,
    ];
    

5. API Integration

  • Validate PIN in API:
    public function login(Request $request)
    {
        $credentials = $request->only(['email', 'password', 'pin']);
        if (!RFAuthenticator::verifyPin($request->user(), $credentials['pin'])) {
            return response()->json(['error' => 'Invalid PIN'], 401);
        }
        // Proceed with login
    }
    

Advanced Patterns

Customizing Security Logic

  • Override PIN Generation:
    // In User model
    public function setSecurityPin($pin = null)
    {
        $pin = $pin ?? $this->generateCustomPin();
        parent::setSecurityPin($pin);
    }
    
    protected function generateCustomPin()
    {
        return Str::random(6); // Alphanumeric PIN
    }
    
  • Extend Mnemonic Storage:
    // Encrypt mnemonic before saving
    public function setMnemonicKeyAttribute($value)
    {
        $this->attributes['mnemonic_key'] = encrypt($value);
    }
    

Event Listeners

  • Log Security Events:
    // In EventServiceProvider
    protected $listen = [
        \RaditzFarhan\UserSecurity\Events\PinVerified::class => [
            \App\Listeners\LogSecurityEvent::class,
        ],
    ];
    

Testing

  • Unit Tests for PIN Validation:
    public function test_pin_validation()
    {
        $user = User::factory()->create();
        $user->setSecurityPin('123456');
    
        $this->assertTrue(RFAuthenticator::verifyPin($user, '123456'));
        $this->assertFalse(RFAuthenticator::verifyPin($user, '000000'));
    }
    

Gotchas and Tips

Pitfalls

  1. Migration Conflicts

    • The package adds security_pin, mnemonic_key, two_factor_secret, and two_factor_recovery_codes columns to the users table. If your schema already has these columns, manually resolve conflicts or rename existing columns to avoid overwrites.
  2. PIN Brute Force

    • The default implementation does not include rate-limiting for PIN attempts. Add middleware to throttle requests:
      // app/Http/Middleware/ThrottlePinAttempts.php
      public function handle($request, Closure $next)
      {
          $key = $request->ip() . '|' . $request->user()->id;
          if (request()->attempts($key, 5)) {
              return response()->json(['error' => 'Too many attempts'], 429);
          }
          return $next($request);
      }
      
  3. Mnemonic Key Exposure

    • The mnemonic key is stored in plaintext by default. Always:
      • Display it securely (e.g., in a modal with a "hide" button).
      • Consider encrypting it in the database (override setMnemonicKeyAttribute).
      • Warn users to keep it offline.
  4. 2FA Secret Management

    • The two_factor_secret is base32-encoded but stored as plaintext. For production:
      • Use Laravel's encrypt() to store the secret.
      • Clear the secret after successful verification if using temporary codes.
  5. Lumen Facades

    • Lumen requires explicit facade registration. Forgetting $app->withFacades(true) will cause RFAuthenticator:: calls to fail with Class not found errors.
  6. Session Binding

    • The package does not automatically bind security checks to sessions. Ensure your middleware runs after auth middleware to access the authenticated user:
      // Correct order in Kernel.php
      'auth' => \App\Http\Middleware\Authenticate::class,
      'pin' => \RaditzFarhan\UserSecurity\Http\Middleware\CheckPin::class,
      

Debugging Tips

  1. Verify Config

    • Check config/user-security.php for misconfigured values (e.g., pin_length set to 0).
  2. Check Database

    • Ensure the users table has the expected columns:
      SELECT column_name FROM information_schema.columns
      WHERE table_name = 'users' AND column_name LIKE '%security%';
      
  3. Log Facade Calls

    • Temporarily add logging to the facade to debug silent failures:
      // In RFAuthenticator facade
      public static function verifyPin
      
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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor