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

Php Authenticator Laravel Package

chillerlan/php-authenticator

PHP 8.4+ library to generate and verify HOTP (RFC 4226) and TOTP (RFC 6238) one-time passwords, compatible with Google Authenticator-style apps. Includes optional Steam Guard time sync plus constant-time encoding helpers for safer key handling.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require chillerlan/php-authenticator
    
  2. Basic TOTP (Time-Based) Usage:

    use chillerlan\Authenticator\Authenticator;
    
    $auth = new Authenticator();
    $secret = $auth->createSecret(); // Generate a secret (e.g., "JBSWY3DPEHPK3PXP")
    $auth->setSecret($secret); // Store the secret for future use
    
    // Generate a QR code URI for Google Authenticator
    $uri = $auth->getUri('MyApp', 'MyCompany');
    // Output: otpauth://totp/MyApp?secret=JBSWY3DPEHPK3PXP&issuer=MyCompany
    
  3. Verify a Code:

    $userInput = '123456'; // User's input
    if ($auth->verify($userInput)) {
        // Valid OTP
    }
    

First Use Case: User Onboarding

  • Generate a secret during user registration.
  • Display a QR code (using a library like endroid/qr-code) and the secret as a fallback.
  • Store the secret in the database (e.g., users.otp_secret).
  • Verify the OTP during login.

Implementation Patterns

Workflow: TOTP (Time-Based) Authentication

  1. Setup:

    $auth = new Authenticator([
        'digits' => 6,
        'period' => 30,
        'algorithm' => AuthenticatorInterface::ALGO_SHA256,
    ]);
    
  2. User Registration:

    $secret = $auth->createSecret();
    $user->otp_secret = $secret;
    $user->save();
    
    // Generate QR code URI
    $uri = $auth->getUri('user@example.com', 'MyApp');
    
  3. Login Flow:

    $userInput = request('otp_code');
    $auth->setSecret($user->otp_secret);
    if ($auth->verify($userInput)) {
        // Authenticate user
    }
    

Workflow: HOTP (Counter-Based) Authentication

  1. Setup:

    $auth = new Authenticator([
        'mode' => AuthenticatorInterface::HOTP,
    ]);
    
  2. User Registration:

    $secret = $auth->createSecret();
    $user->otp_secret = $secret;
    $user->otp_counter = 0; // Initialize counter
    $user->save();
    
  3. Login Flow:

    $userInput = request('otp_code');
    $auth->setSecret($user->otp_secret);
    if ($auth->verify($userInput, $user->otp_counter)) {
        $user->otp_counter++; // Increment counter
        $user->save();
        // Authenticate user
    }
    

Integration with Laravel

  1. Service Provider:

    use chillerlan\Authenticator\Authenticator;
    
    class AuthServiceProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->singleton(Authenticator::class, function () {
                return new Authenticator(config('auth.otp'));
            });
        }
    }
    
  2. Config (config/auth.php):

    'otp' => [
        'digits' => 6,
        'period' => 30,
        'algorithm' => \chillerlan\Authenticator\AuthenticatorInterface::ALGO_SHA256,
        'mode' => \chillerlan\Authenticator\AuthenticatorInterface::TOTP,
    ],
    
  3. Middleware for OTP Verification:

    use chillerlan\Authenticator\Authenticator;
    
    class VerifyOtpMiddleware
    {
        public function handle($request, Closure $next)
        {
            $auth = app(Authenticator::class);
            $auth->setSecret(auth()->user()->otp_secret);
    
            if (!$auth->verify($request->otp_code)) {
                return redirect()->back()->withErrors(['otp' => 'Invalid code']);
            }
    
            return $next($request);
        }
    }
    

Extending Functionality

  • Custom Secret Storage: Use AuthenticatorInterface::setRawSecret() to store the raw binary secret in the database (e.g., users.otp_secret_raw).

    $auth->setRawSecret($rawSecret); // Store raw binary secret
    $auth->setSecret($encodedSecret); // Use encoded secret for verification
    
  • Dynamic Options: Override options per user:

    $auth = new Authenticator([
        'digits' => $user->otp_digits ?? 6,
        'period' => $user->otp_period ?? 30,
    ]);
    

Gotchas and Tips

Pitfalls

  1. Secret Storage:

    • Always store secrets securely (e.g., encrypted in the database).
    • Avoid logging or exposing secrets in error messages.
    • Use setRawSecret() for raw binary storage if needed.
  2. Time Synchronization:

    • For TOTP, ensure server time is accurate. Use useLocalTime: false and forceTimeRefresh: true for Steam Guard compatibility:
      $auth = new Authenticator([
          'useLocalTime' => false,
          'forceTimeRefresh' => true,
      ]);
      
  3. Adjacent Codes:

    • Default adjacent: 1 allows verification of the current and previous code.
    • Increase cautiously (e.g., adjacent: 2 for 1-minute window with 30-second period).
  4. HOTP Counter:

    • Ensure the counter is incremented after successful verification to avoid replay attacks.
    • Store the counter in the database (e.g., users.otp_counter).
  5. URI Compatibility:

    • Not all authenticator apps support all URI parameters (e.g., algorithm).
    • Test with Google Authenticator and other apps before relying on custom settings.
  6. PHP Extensions:

    • Requires ext-sodium for constant-time encoding (fallback to paragonie/constant_time_encoding if missing).
    • ext-curl is needed for Steam Guard server time sync.

Debugging Tips

  1. Verify Secrets:

    • Manually check a secret using 2FA Generator or Google Authenticator.
    • Compare generated codes with Authenticator::code():
      $auth->setSecret($user->otp_secret);
      $expectedCode = $auth->code(); // Current TOTP code
      
  2. Time Offsets:

    • Debug time issues with:
      $auth->setOptions(['time_offset' => 30]); // Adjust for timezone
      
  3. HOTP Counter:

    • Log the counter value during verification:
      $auth->verify($otp, $counter);
      logger("HOTP Counter: $counter");
      
  4. Algorithm Mismatch:

    • Ensure the algorithm in the URI matches the one used in Authenticator:
      $uri = $auth->getUri('label', 'issuer', null, false); // Include algorithm in URI
      

Extension Points

  1. Custom Encoders:

    • Implement EncoderInterface for custom encoding/decoding (e.g., for legacy systems).
  2. Event Hooks:

    • Extend Authenticator to trigger events (e.g., before/after verification):
      class CustomAuthenticator extends Authenticator
      {
          public function verify($otp, $data = null)
          {
              event(new VerifyingOtp($otp, $data));
              $result = parent::verify($otp, $data);
              event(new OtpVerified($result));
              return $result;
          }
      }
      
  3. Database Models:

    • Add OTP methods to Laravel models:
      use chillerlan\Authenticator\Authenticator;
      
      class User extends Model
      {
          public function verifyOtp($code)
          {
              $auth = app(Authenticator::class);
              $auth->setSecret($this->otp_secret);
              return $auth->verify($code);
          }
      }
      
  4. Fallback Codes:

    • Implement backup codes (not part of the package) using a separate table:
      // Example: Generate and store backup codes
      $backupCodes = str_split(str_random(16));
      $user->backup_codes = json_encode($backupCodes);
      $user->save();
      

Performance Notes

  • Caching: Cache generated URIs or secrets if they rarely change (e.g., during user onboarding).
  • Batch Verification: For bulk operations (e.g., admin
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
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
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