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

Otp Bundle Laravel Package

afrikpay/otp-bundle

Symfony bundle for generating and validating one-time passwords (OTP). Install via Composer, register the bundle, run migrations, and use console commands to manage OTP workflows (create/enable/disable/run) for verification flows and scheduled processing.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require afrikpay/otp-bundle
    

    Add to config/bundles.php (Symfony 4.3+):

    return [
        // ...
        Afrikpay\OTPBundle\AfrikPayOTPBundle::class => ['all' => true],
    ];
    
  2. Database Migration: Run migrations to create the OTP-related tables:

    php bin/console make:migration
    php bin/console doctrine:migrations:migrate
    
  3. First Use Case: Generate and send an OTP via a controller:

    use Afrikpay\OTPBundle\Service\OTPService;
    
    class AuthController extends AbstractController
    {
        public function sendOtp(OTPService $otpService)
        {
            $phone = '+2348123456789';
            $otp = $otpService->generateAndSend($phone);
            return new JsonResponse(['otp_id' => $otp->getId()]);
        }
    }
    
  4. Verify OTP:

    public function verifyOtp(OTPService $otpService, Request $request)
    {
        $otpId = $request->request->get('otp_id');
        $code = $request->request->get('code');
        $result = $otpService->verify($otpId, $code);
        return new JsonResponse($result);
    }
    

Implementation Patterns

Core Workflows

  1. OTP Generation & Sending:

    // Generate and send OTP (auto-expiry: 5 mins by default)
    $otp = $otpService->generateAndSend($phoneNumber, [
        'template' => 'Your OTP is {code}. Valid for 5 mins.',
        'expiry' => 300, // 5 mins in seconds
    ]);
    
  2. Manual OTP Handling:

    // Generate OTP without sending
    $otp = $otpService->generate($phoneNumber);
    
    // Send existing OTP
    $otpService->send($otp);
    
  3. Verification:

    $result = $otpService->verify($otpId, $userInputCode);
    // Returns: ['success' => true/false, 'message' => '...']
    
  4. Resending OTP:

    $otpService->resend($otpId); // Resends last OTP for this phone
    

Integration Tips

  1. Event Listeners: Subscribe to OTP events (e.g., otp.sent, otp.verified) in config/services.yaml:

    services:
        App\EventListener\OTPListener:
            tags:
                - { name: kernel.event_listener, event: otp.sent, method: onOtpSent }
    
  2. Custom Templates: Override default SMS templates in config/packages/afrikpay_otp.yaml:

    afrikpay_otp:
        templates:
            default: "Your verification code is {code}. Do not share it."
    
  3. Rate Limiting: Use Symfony’s rate limiter to restrict OTP requests:

    use Symfony\Component\RateLimiter\RateLimiterFactory;
    
    $factory = new RateLimiterFactory();
    $limiter = $factory->create($request->getClientIp());
    if (!$limiter->consume(5, 60)) {
        throw new \RuntimeException('Too many requests');
    }
    
  4. Testing: Mock the OTPService in tests:

    $otpService = $this->createMock(OTPService::class);
    $otpService->method('verify')->willReturn(['success' => true]);
    

Gotchas and Tips

Pitfalls

  1. Cron Dependency:

    • The bundle assumes a cron job (cron:run) for background tasks (e.g., OTP expiry cleanup).
    • Fix: Manually trigger expiry checks in a command or use Symfony Messenger for async tasks:
      $otpService->cleanupExpired(); // Call this periodically
      
  2. Database Schema:

    • Migrations may fail if the otp table already exists.
    • Tip: Check src/Resources/migrations/ for the schema and adjust manually if needed.
  3. Phone Number Format:

    • The bundle expects E.164 format (e.g., +2348123456789).
    • Tip: Sanitize input:
      $phone = preg_replace('/[^0-9+]/', '', $rawPhone);
      
  4. SMS Provider Integration:

    • The bundle lacks a built-in SMS provider (e.g., Afrikpay API).
    • Workaround: Extend the Afrikpay\OTPBundle\Service\SmsProviderInterface:
      class AfrikpaySmsProvider implements SmsProviderInterface
      {
          public function send(string $phone, string $message): bool
          {
              // Integrate with Afrikpay API
          }
      }
      
      Register it in services.yaml:
      afrikpay_otp.sms_provider: '@App\Service\AfrikpaySmsProvider'
      

Debugging Tips

  1. Enable Logging: Add to config/packages/monolog.yaml:

    handlers:
        otp:
            type: stream
            path: "%kernel.logs_dir%/otp.log"
            level: debug
            channels: ["afrikpay_otp"]
    
  2. OTP Expiry:

    • Default expiry is 5 minutes. Override in config:
      afrikpay_otp:
          default_expiry: 600 # 10 minutes
      
  3. Verification Errors:

    • Common causes:
      • OTP ID not found (check otp_id in DB).
      • Code mismatch (case-sensitive).
      • Expired OTP (log expiry time in otp.sent event).
  4. Testing Locally:

    • Use a mock SMS provider for testing:
      $otpService->setSmsProvider(new MockSmsProvider());
      

Extension Points

  1. Custom OTP Storage: Extend Afrikpay\OTPBundle\Entity\OTP or use a custom repository:

    class CustomOTPRepository extends ServiceEntityRepository
    {
        public function findByPhone(string $phone): ?OTP
        {
            // Custom logic
        }
    }
    
  2. Multi-Channel OTP: Support email/email OTP by implementing MultiChannelOTPService:

    class MultiChannelOTPService extends OTPService
    {
        public function sendViaEmail(string $email, string $code): bool
        {
            // Logic for email OTP
        }
    }
    
  3. Webhook Validation: Validate OTPs via webhooks (e.g., Afrikpay callback):

    use Afrikpay\OTPBundle\Event\OTPWebhookEvent;
    
    public function onOtpWebhook(OTPWebhookEvent $event)
    {
        if ($event->isValid()) {
            $otpService->markAsVerified($event->getOtpId());
        }
    }
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
codifyo/ts-generator-bundle
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