PHPackages                             addicta/otp - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. addicta/otp

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

addicta/otp
===========

Multi-provider OTP package for Laravel

0.4.0(5mo ago)01MITPHPPHP ^8.2|^8.3|^8.4

Since Dec 13Pushed 5mo agoCompare

[ Source](https://github.com/AhmedRefaatA/Laravel-Otp)[ Packagist](https://packagist.org/packages/addicta/otp)[ RSS](/packages/addicta-otp/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (5)Versions (2)Used By (0)

Addicta OTP Package
===================

[](#addicta-otp-package)

A comprehensive Laravel package for sending and verifying One-Time Passwords (OTP) via SMS using multiple providers including Twilio and Unifonic.

Features
--------

[](#features)

- 📡 **Multi-Channel Support**: Send OTPs via Phone (SMS) or Email
- 🔐 **Multi-Provider Support**: Twilio (SMS &amp; Verify API) and Unifonic providers
- ✨ **Twilio Verify Service**: Full support for Twilio's Verify API with custom OTP codes
- 📧 **Beautiful Email Templates**: Professional, responsive HTML email templates
- 🛡️ **Security Features**: Rate limiting, attempt tracking, and automatic blocking
- ⏰ **Configurable Expiry**: Customizable OTP expiration times
- 🔄 **Resend Protection**: Prevents spam with configurable resend delays
- 🧪 **Fully Tested**: Comprehensive test suite with 16 tests
- 🎯 **Laravel Integration**: Service provider, facades, and auto-discovery
- 📱 **Easy to Use**: Simple API for generating and verifying OTPs
- 🌍 **Multi-Language**: Built-in English and Arabic translations for both SMS and Email

Installation
------------

[](#installation)

### Via Composer

[](#via-composer)

```
composer require one-studio/otp
```

### Laravel Auto-Discovery

[](#laravel-auto-discovery)

The package will be automatically discovered by Laravel. If you're using Laravel 5.5+, no additional configuration is required.

### Manual Registration (Laravel &lt; 5.5)

[](#manual-registration-laravel--55)

Add the service provider to your `config/app.php`:

```
'providers' => [
    // ...
    Addicta\Otp\OtpServiceProvider::class,
],
```

Add the facade alias:

```
'aliases' => [
    // ...
    'Otp' => Addicta\Otp\Facades\Otp::class,
],
```

Configuration
-------------

[](#configuration)

### Publishing Configuration and Translations

[](#publishing-configuration-and-translations)

Publish the configuration file:

```
php artisan vendor:publish --provider="Addicta\Otp\OtpServiceProvider" --tag="otp-config"
```

Publish the translation files:

```
php artisan vendor:publish --provider="Addicta\Otp\OtpServiceProvider" --tag="otp-translations"
```

This will create:

- `config/otp.php` - Configuration file
- `lang/vendor/otp/en/otp.php` - English translations
- `lang/vendor/otp/ar/otp.php` - Arabic translations

### Environment Variables

[](#environment-variables)

Add the following environment variables to your `.env` file:

```
# Default Channel: 'phone' or 'email' (default: phone)
OTP_DEFAULT_CHANNEL=phone

# OTP Provider for phone channel (twilio or unifonic)
OTP_PROVIDER=twilio

# Twilio Configuration
TWILIO_ACCOUNT_SID=your_twilio_account_sid
TWILIO_AUTH_TOKEN=your_twilio_auth_token

# Twilio Service Type: 'sms' for direct SMS or 'verify' for Twilio Verify API
TWILIO_SERVICE_TYPE=sms

# Required for SMS service type
TWILIO_FROM=your_twilio_phone_number

# Required for Verify service type
TWILIO_VERIFICATION_SID=your_twilio_verification_sid

# Unifonic Configuration (if using Unifonic)
UNIFONIC_APP_SID=your_unifonic_app_sid
UNIFONIC_SENDER_ID=your_unifonic_sender_id

# Email Configuration
OTP_EMAIL_FROM_ADDRESS=noreply@yourapp.com
OTP_EMAIL_FROM_NAME="Your App Name"
OTP_EMAIL_SUBJECT="Your Verification Code"

# OTP Settings
OTP_LENGTH=4
OTP_EXPIRY=5
MAX_ATTEMPTS=3
RESEND_DELAY=60
BLOCK_DURATION=30

# Test Mode Settings
OTP_TEST_MODE=false
OTP_TEST_CODE=8888
```

### Configuration File

[](#configuration-file)

The published configuration file (`config/otp.php`) contains:

```
return [
    // Default channel for OTP delivery: 'phone' or 'email'
    'default_channel' => env('OTP_DEFAULT_CHANNEL', 'phone'),

    // Default provider for phone OTPs
    'default' => env('OTP_PROVIDER', 'twilio'),

    // SMS/Phone providers
    'providers' => [
        'twilio' => [
            'driver' => 'twilio',
            'account_sid' => env('TWILIO_ACCOUNT_SID'),
            'auth_token' => env('TWILIO_AUTH_TOKEN'),
            'service_type' => env('TWILIO_SERVICE_TYPE', 'sms'), // 'sms' or 'verify'
            'verification_sid' => env('TWILIO_VERIFICATION_SID'), // Required for 'verify' service
            'from' => env('TWILIO_FROM'), // Required for 'sms' service
        ],
        'unifonic' => [
            'driver' => 'unifonic',
            'app_sid' => env('UNIFONIC_APP_SID'),
            'sender_id' => env('UNIFONIC_SENDER_ID'),
        ],
    ],

    // Email provider configuration
    'email' => [
        'driver' => 'email',
        'from_address' => env('OTP_EMAIL_FROM_ADDRESS', env('MAIL_FROM_ADDRESS', 'noreply@example.com')),
        'from_name' => env('OTP_EMAIL_FROM_NAME', env('MAIL_FROM_NAME', 'OTP Service')),
        'subject' => env('OTP_EMAIL_SUBJECT', 'Your Verification Code'),
    ],

    'otp_length' => env('OTP_LENGTH', 4),
    'otp_expiry' => env('OTP_EXPIRY', 5), // minutes
    'max_attempts' => env('MAX_ATTEMPTS', 3),
    'resend_delay' => env('RESEND_DELAY', 60), // seconds
    'block_duration' => env('BLOCK_DURATION', 30), // minutes after max attempts

    // Rate limiting configuration
    'rate_limit' => [
        'enabled' => env('OTP_RATE_LIMIT_ENABLED', true),
        'max_requests_per_hour' => env('OTP_MAX_REQUESTS_PER_HOUR', 3), // per phone number or email
        'block_duration' => env('OTP_BLOCK_DURATION', 60), // minutes to block after limit exceeded
    ],

    // Test mode configuration
    'test_mode' => env('OTP_TEST_MODE', false),
    'test_otp' => env('OTP_TEST_CODE', '8888'),
    'test_numbers' => [
        '+1234567890',
        '+9876543210',
        // Add more test numbers as needed
    ],
    'test_emails' => [
        'test@example.com',
        'demo@example.com',
        // Add more test emails as needed
    ],
];
```

Usage
-----

[](#usage)

### Multi-Channel Support (Phone &amp; Email)

[](#multi-channel-support-phone--email)

The package supports sending OTPs through two channels: **Phone (SMS)** and **Email**. By default, OTPs are sent via phone, but you can easily switch channels.

#### Default Channel Configuration

[](#default-channel-configuration)

Set your preferred default channel in `.env`:

```
OTP_DEFAULT_CHANNEL=phone  # or 'email'
```

#### Sending OTP via Phone (Default)

[](#sending-otp-via-phone-default)

```
use Addicta\Otp\Facades\Otp;

// Send OTP to phone number (uses default channel: phone)
$result = Otp::generate('+1234567890');

// Or explicitly specify phone channel
$result = Otp::generate('+1234567890', 'phone');

if ($result['success']) {
    echo "OTP sent via SMS!";
    echo "Channel: " . $result['channel']; // 'phone'
}
```

#### Sending OTP via Email

[](#sending-otp-via-email)

```
use Addicta\Otp\Facades\Otp;

// Send OTP to email address
$result = Otp::generate('user@example.com', 'email');

if ($result['success']) {
    echo "OTP sent via email!";
    echo "Channel: " . $result['channel']; // 'email'
}
```

#### Verifying OTP (Works for Both Channels)

[](#verifying-otp-works-for-both-channels)

```
// Verification works the same way for both channels
$phone = '+1234567890';
$verifyResult = Otp::verify($phone, '1234');

// Or for email
$email = 'user@example.com';
$verifyResult = Otp::verify($email, '1234');

if ($verifyResult['success']) {
    echo "Verified successfully!";
}
```

#### Dynamic Channel Selection

[](#dynamic-channel-selection)

You can let users choose their preferred verification method:

```
public function sendOtp(Request $request)
{
    $recipient = $request->input('recipient'); // phone or email
    $channel = $request->input('channel', 'phone'); // default to phone

    $result = Otp::generate($recipient, $channel);

    return response()->json($result);
}
```

#### Channel-Specific Features

[](#channel-specific-features)

**Phone Channel:**

- Uses configured SMS provider (Twilio, Unifonic)
- Supports Twilio Verify API
- Custom message templates
- Multilingual SMS messages

**Email Channel:**

- Beautiful HTML email templates
- Plain text fallback
- Customizable sender information
- Responsive design
- Security warnings included

#### Email Template Customization

[](#email-template-customization)

Publish the email views to customize them:

```
php artisan vendor:publish --provider="Addicta\Otp\OtpServiceProvider" --tag="otp-views"
```

This creates:

- `resources/views/vendor/otp/emails/otp.blade.php` - HTML email template
- `resources/views/vendor/otp/emails/otp-text.blade.php` - Plain text template

#### Response Format

[](#response-format)

Both channels return the same response structure:

```
[
    'success' => true,
    'message' => 'OTP sent successfully.',
    'remaining_time' => 60,
    'type' => 'success',
    'channel' => 'email' // or 'phone'
]
```

### Multi-Language Support

[](#multi-language-support)

The package supports multiple languages with built-in English and Arabic translations. You can customize messages by publishing and editing the translation files.

**Available Languages:**

- English (`en`)
- Arabic (`ar`)

**Setting Application Locale:**

In your Laravel application, set the locale in `config/app.php`:

```
'locale' => 'ar', // For Arabic
'locale' => 'en', // For English
```

Or dynamically in your application:

```
App::setLocale('ar'); // Switch to Arabic
App::setLocale('en'); // Switch to English
```

**Customizing Messages:**

After publishing translations, you can customize the messages in:

- `lang/vendor/otp/en/otp.php` - English messages
- `lang/vendor/otp/ar/otp.php` - Arabic messages

### Rate Limiting

[](#rate-limiting)

The package includes built-in rate limiting to prevent abuse and excessive OTP requests. Rate limiting uses a rolling window approach - tracking requests in the last 60 minutes per phone number with automatic blocking.

### Configuration

[](#configuration-1)

Rate limiting can be configured in your `.env` file:

```
# Enable/disable rate limiting
OTP_RATE_LIMIT_ENABLED=true

# Maximum requests per phone number per hour
OTP_MAX_REQUESTS_PER_HOUR=3

# Block duration in minutes after limit exceeded
OTP_BLOCK_DURATION=60
```

### How It Works

[](#how-it-works)

- **Per Phone Number**: Rate limits are applied individually to each phone number
- **Rolling Window**: Tracks requests in the last 60 minutes (not fixed hourly blocks)
- **Automatic Blocking**: When limit is exceeded, phone is blocked for specified duration
- **Block Duration**: Configurable block time (default: 60 minutes)
- **Cache-Based**: Uses Laravel's cache system for tracking with automatic cleanup

### Rate Limit Response

[](#rate-limit-response)

When rate limits are exceeded, the service returns:

```
[
    'success' => false,
    'message' => 'Rate limit exceeded. Maximum 3 requests per hour allowed. Blocked for 60 minutes.',
    'remaining_time' => 3600, // seconds until unblocked
    'type' => 'rate_limited'
]
```

When phone is blocked, the service returns:

```
[
    'success' => false,
    'message' => 'Phone number is blocked due to rate limiting. Try again in 45 minutes.',
    'remaining_time' => 2700, // seconds remaining
    'type' => 'rate_limited'
]
```

### Response Types

[](#response-types)

The `type` field indicates the reason for the response:

- `success` - OTP sent successfully
- `rate_limited` - Rate limit exceeded or phone blocked
- `blocked` - Phone blocked due to failed attempts
- `resend_delay` - Resend delay active
- `send_failed` - Failed to send OTP

### Disabling Rate Limiting

[](#disabling-rate-limiting)

To disable rate limiting entirely:

```
OTP_RATE_LIMIT_ENABLED=false
```

### Use Cases

[](#use-cases)

- **Production**: Enable rate limiting to prevent abuse
- **Development**: Disable rate limiting for easier testing
- **High Traffic**: Adjust limits based on your application needs

Test Mode
---------

[](#test-mode)

The package includes a built-in test mode for development and testing purposes. This allows you to test OTP functionality without sending actual SMS messages.

**Enabling Test Mode:**

1. **Global Test Mode** - Enable for all phone numbers:

```
OTP_TEST_MODE=true
OTP_TEST_CODE=8888

# Rate limiting configuration
OTP_RATE_LIMIT_ENABLED=true
OTP_MAX_REQUESTS_PER_HOUR=3
OTP_BLOCK_DURATION=60
```

2. **Specific Test Numbers** - Add phone numbers to test list:

```
// In config/otp.php
'test_numbers' => [
    '+1234567890',
    '+9876543210',
    '+201120305686', // Your test number
],
```

**Test Mode Behavior:**

- **No SMS Sent**: When test mode is active, no actual SMS is sent
- **Fixed OTP**: Uses the configured test OTP code (default: 8888)
- **Same Verification**: Test OTPs work exactly like real OTPs
- **Response Indicators**: Test mode responses use the same format as regular responses

**Test Mode Response Example:**

```
[
    'success' => true,
    'message' => 'OTP sent successfully.',
    'remaining_time' => 60,
    'type' => 'success'
]
```

**Use Cases:**

- Development and testing
- Demo environments
- CI/CD pipelines
- Unit testing
- Avoiding SMS costs during development

### Using the Facade

[](#using-the-facade)

```
use Addicta\Otp\Facades\Otp;

// Generate OTP
$result = Otp::generate('+1234567890');

if ($result['success']) {
    echo "OTP sent successfully!";
    echo "Expires in: " . $result['expires_in'] . " seconds";
} else {
    echo "Failed to send OTP: " . $result['message'];
}

// Verify OTP
$verifyResult = Otp::verify('+1234567890', '1234');

if ($verifyResult['success']) {
    echo "OTP verified successfully!";
} else {
    echo "Verification failed: " . $verifyResult['message'];
    if (isset($verifyResult['remaining_attempts'])) {
        echo "Remaining attempts: " . $verifyResult['remaining_attempts'];
    }
}
```

### Using Dependency Injection

[](#using-dependency-injection)

```
use Addicta\Otp\OtpService;

class AuthController extends Controller
{
    protected $otpService;

f
    public function __construct(OtpService $otpService)
    {
        $this->otpService = $otpService;
    }

    public function sendOtp(Request $request)
    {
        $phone = $request->input('phone');
        $result = $this->otpService->generate($phone);

        return response()->json($result);
    }
f
    public function verifyOtp(Request $request)
    {
        $phone = $request->input('phone');
        $code = $request->input('code');

        $result = $this->otpService->verify($phone, $code);

        return response()->json($result);
    }
}
```

### Using the Manager Directly

[](#using-the-manager-directly)

```
use Addicta\Otp\OtpManager;

$manager = app(OtpManager::class);
$provider = $manager->driver(); // Gets the default provider
$result = $provider->send('+1234567890', 'Your OTP is: 1234');
```

### Twilio Verify Service Usage

[](#twilio-verify-service-usage)

When using Twilio Verify service, the package handles OTP generation and verification seamlessly:

#### Sending OTP with Verify Service

[](#sending-otp-with-verify-service)

```
use Addicta\Otp\Facades\Otp;

// Configure .env for Verify service
// TWILIO_SERVICE_TYPE=verify
// TWILIO_VERIFICATION_SID=VAxxxxxxxxxxxxx

// Generate and send OTP using Verify API
$result = Otp::generate('+1234567890');

if ($result['success']) {
    // OTP sent via Twilio Verify with custom code
    echo "Verification code sent!";
    echo "User will receive SMS from Twilio Verify service";
} else {
    echo "Error: " . $result['message'];
}
```

#### Verifying OTP with Verify Service

[](#verifying-otp-with-verify-service)

```
// The package handles verification automatically
$verifyResult = Otp::verify('+1234567890', '1234');

if ($verifyResult['success']) {
    // OTP verified successfully
    // User can proceed with registration/login
    echo "Phone number verified!";
} else {
    echo "Invalid code: " . $verifyResult['message'];
}
```

#### Switching Between SMS and Verify

[](#switching-between-sms-and-verify)

You can easily switch between service types without changing your application code:

**For SMS Service:**

```
TWILIO_SERVICE_TYPE=sms
TWILIO_FROM=+1234567890
```

**For Verify Service:**

```
TWILIO_SERVICE_TYPE=verify
TWILIO_VERIFICATION_SID=VAxxxxxxxxxxxxx
```

Your application code remains the same regardless of which service you use!

API Reference
-------------

[](#api-reference)

### OtpService Methods

[](#otpservice-methods)

#### `generate(string $phone): array`

[](#generatestring-phone-array)

Generates and sends an OTP to the specified phone number.

**Parameters:**

- `$phone` (string): Phone number in international format (e.g., +1234567890)

**Returns:**

```
[
    'success' => bool,
    'message' => string,
    'expires_in' => int, // seconds
    'remaining_time' => int, // if resend delay active
    'blocked_until' => Carbon, // if blocked
]
```

#### `verify(string $phone, string $code): array`

[](#verifystring-phone-string-code-array)

Verifies an OTP code for the specified phone number.

**Parameters:**

- `$phone` (string): Phone number in international format
- `$code` (string): OTP code to verify

**Returns:**

```
[
    'success' => bool,
    'message' => string,
    'remaining_attempts' => int, // if verification failed
]
```

Security Features
-----------------

[](#security-features)

### Rate Limiting

[](#rate-limiting-1)

- **Resend Delay**: Prevents immediate resending of OTPs (default: 60 seconds)
- **Max Attempts**: Limits verification attempts (default: 3 attempts)
- **Block Duration**: Temporary blocking after max attempts exceeded (default: 30 minutes)

### OTP Management

[](#otp-management)

- **Expiry**: OTPs expire after configured time (default: 5 minutes)
- **Single Use**: OTPs are automatically removed after successful verification
- **Cache Storage**: OTPs are stored securely in Laravel's cache system

Error Handling
--------------

[](#error-handling)

The package returns detailed error messages for various scenarios. All messages are translatable and will be returned in the current application locale:

**English Messages:**

```
// Rate limiting
[
    'success' => false,
    'message' => 'Please wait 45 seconds before requesting a new OTP.',
    'remaining_time' => 45
]

// Blocked phone
[
    'success' => false,
    'message' => 'Too many attempts. Please try again later.',
    'blocked_until' => Carbon::now()->addMinutes(30)
]

// Invalid OTP
[
    'success' => false,
    'message' => 'Invalid OTP.',
    'remaining_attempts' => 2
]

// Expired OTP
[
    'success' => false,
    'message' => 'OTP expired or not found.'
]
```

**Arabic Messages (when locale is set to 'ar'):**

```
// Rate limiting
[
    'success' => false,
    'message' => 'يرجى الانتظار 45 ثانية قبل طلب رمز تحقق جديد.',
    'remaining_time' => 45
]

// Blocked phone
[
    'success' => false,
    'message' => 'محاولات كثيرة جداً. يرجى المحاولة مرة أخرى لاحقاً.',
    'blocked_until' => Carbon::now()->addMinutes(30)
]

// Invalid OTP
[
    'success' => false,
    'message' => 'رمز التحقق غير صحيح.',
    'remaining_attempts' => 2
]

// Expired OTP
[
    'success' => false,
    'message' => 'انتهت صلاحية رمز التحقق أو لم يتم العثور عليه.'
]
```

Testing
-------

[](#testing)

The package includes comprehensive tests. Run them using:

```
# Run all tests
./vendor/bin/phpunit

# Run specific test suites
./vendor/bin/phpunit --testsuite=Unit
./vendor/bin/phpunit --testsuite=Feature

# Run with coverage
./vendor/bin/phpunit --coverage-html coverage
```

Supported Providers
-------------------

[](#supported-providers)

### Twilio

[](#twilio)

The package supports two Twilio service types:

#### 1. SMS Service (Direct Messaging)

[](#1-sms-service-direct-messaging)

- **Service Type**: `sms`
- **Best For**: Simple OTP delivery with custom message formatting
- **Required Config**: `account_sid`, `auth_token`, `from`
- **Features**:
    - Full control over message content
    - Custom message templates with multilingual support
    - Direct SMS delivery
    - Lower cost per message

**Configuration Example:**

```
TWILIO_SERVICE_TYPE=sms
TWILIO_ACCOUNT_SID=your_account_sid
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_FROM=+1234567890
```

#### 2. Verify API Service (Recommended)

[](#2-verify-api-service-recommended)

- **Service Type**: `verify`
- **Best For**: Enhanced security and compliance features
- **Required Config**: `account_sid`, `auth_token`, `verification_sid`
- **Features**:
    - Built-in fraud detection
    - Automatic rate limiting and abuse prevention
    - Carrier-level integrations for better delivery
    - Custom OTP code support
    - Geographic and carrier analytics
    - Compliance with regulatory requirements

**Configuration Example:**

```
TWILIO_SERVICE_TYPE=verify
TWILIO_ACCOUNT_SID=your_account_sid
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_VERIFICATION_SID=your_verification_sid
```

**Getting Your Verification SID:**

1. Log in to your [Twilio Console](https://console.twilio.com/)
2. Navigate to **Verify** → **Services**
3. Create a new Verify Service or select an existing one
4. Copy the **Service SID** (starts with VA...)

**Key Differences:**

FeatureSMS ServiceVerify ServiceMessage ControlFull customizationTemplate-basedFraud DetectionManualBuilt-inDelivery OptimizationStandardCarrier-optimizedAnalyticsBasicAdvancedComplianceManualAutomaticSetup ComplexitySimpleModerateCostLowerHigher**Choosing the Right Service:**

- Use **SMS** for: Simple applications, full message control, budget-conscious projects
- Use **Verify** for: Production applications, enhanced security, compliance requirements

**Documentation**:

- [Twilio SMS API](https://www.twilio.com/docs/sms)
- [Twilio Verify API](https://www.twilio.com/docs/verify/api)

### Unifonic

[](#unifonic)

- **Driver**: `unifonic`
- **Required Config**: `app_sid`, `sender_id`
- **Documentation**: [Unifonic SMS API](https://docs.unifonic.com/)

### Email Provider

[](#email-provider)

The package includes a built-in email provider for sending OTPs via email.

#### Configuration

[](#configuration-2)

The email provider uses Laravel's mail system, so ensure you have your mail driver configured in `config/mail.php` or `.env`:

```
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_username
MAIL_PASSWORD=your_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@yourapp.com
MAIL_FROM_NAME="${APP_NAME}"
```

#### Features

[](#features-1)

- **Beautiful Templates**: Professional, responsive HTML email design
- **Plain Text Fallback**: Automatic plain text version for email clients
- **Customizable**: Publish and modify email templates to match your brand
- **Security Warnings**: Built-in security notices to prevent phishing
- **Multi-Language**: Supports all translated languages (English, Arabic, etc.)

#### Email Template Preview

[](#email-template-preview)

The email includes:

- Clear verification code display
- Expiration time notice
- Security warnings
- Professional styling
- Responsive design for mobile devices

#### Supported Mail Drivers

[](#supported-mail-drivers)

Works with all Laravel mail drivers:

- SMTP
- Mailgun
- Postmark
- Amazon SES
- Sendmail
- Log (for testing)

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 10.0+
- Twilio SDK (for Twilio provider)
- Guzzle HTTP (for Unifonic provider)

License
-------

[](#license)

This package is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

Contributing
------------

[](#contributing)

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

Support
-------

[](#support)

For support, please open an issue on the GitHub repository or contact the maintainer.

Changelog
---------

[](#changelog)

### Version 0.9.0 (Current)

[](#version-090-current)

- **🚀 Multi-Channel Support**: Major feature - Send OTPs via Phone (SMS) or Email
- **📧 Email OTP Provider**: Complete email provider implementation with beautiful HTML templates
- **🎨 Professional Email Templates**: Responsive HTML and plain text email templates
- **🌍 Channel-Aware Translations**: Email-specific messages in English and Arabic
- **⚙️ Configurable Default Channel**: Set default channel via environment variable (phone or email)
- **🧪 Test Mode for Email**: Support for test emails alongside test phone numbers
- **📊 Unified API**: Same API for both channels - just change the recipient and channel parameter
- **🔄 Backward Compatible**: Existing phone-only implementations continue to work without changes

### Version 0.8.0

[](#version-080)

- **Twilio Verify Service**: Added full support for Twilio Verify API alongside traditional SMS service
- **Dual Service Types**: Choose between 'sms' (direct messaging) or 'verify' (Twilio Verify API)
- **Custom OTP with Verify**: Support for custom OTP codes in Twilio Verify service
- **Service-Specific Configuration**: Automatic configuration validation based on selected service type
- **Enhanced Documentation**: Comprehensive guide for choosing and configuring Twilio services
- **Improved Code Structure**: Refactored provider with constants and better separation of concerns

### Version 0.7.0

[](#version-070)

- **Rate Limiting**: Implemented configurable rate limiting per phone number with rolling window approach
- **Rolling Window**: Tracks requests in the last 60 minutes (not fixed hourly blocks) to prevent bypassing limits
- **Unified Response Format**: Simplified all responses to use consistent structure with `success`, `message`, `remaining_time`, and `type` fields
- **Response Type Enum**: Added `OtpResponseType` enum for type-safe response handling
- **Seconds-Based Timing**: All timing fields now use seconds for easier frontend integration
- **Enhanced Security**: Prevents users from bypassing rate limits by waiting for hour changes
- **Improved Testing**: Added comprehensive tests for rolling window rate limiting

### Version 0.1

[](#version-01)

- Initial release
- Twilio and Unifonic provider support
- **Rate limiting per phone number** (hourly and daily limits)
- **Configurable rate limits** via environment variables
- **Rate limit responses** with retry information
- Comprehensive test suite (26 tests)
- Laravel auto-discovery support
- **Multi-language support** (English &amp; Arabic)
- **Translatable messages** for all responses
- **Publishable translation files** for customization
- **Test Mode** for development and testing
- **Test phone numbers** support
- **Fixed test OTP** for consistent testing

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance73

Regular maintenance activity

Popularity1

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

153d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e2e96f3b8b3ebad1be64e6b7444d869dcb9503f91d2cdb88eb84cac0dc9dc7c4?d=identicon)[Addicta](/maintainers/Addicta)

---

Top Contributors

[![AhmedRefaatA](https://avatars.githubusercontent.com/u/71472780?v=4)](https://github.com/AhmedRefaatA "AhmedRefaatA (1 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/addicta-otp/health.svg)

```
[![Health](https://phpackages.com/badges/addicta-otp/health.svg)](https://phpackages.com/packages/addicta-otp)
```

###  Alternatives

[josiasmontag/laravel-recaptchav3

Recaptcha V3 for Laravel package

2641.6M2](/packages/josiasmontag-laravel-recaptchav3)[rahul900day/laravel-captcha

Different types of Captcha implementation for Laravel Application.

10715.9k](/packages/rahul900day-laravel-captcha)[truckersmp/steam-socialite

Laravel Socialite provider for Steam OpenID.

1516.7k](/packages/truckersmp-steam-socialite)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)[pitchanon/facebook-connect

A Laravel package for connecting to the Meta (Facebook) Graph API.

254.3k1](/packages/pitchanon-facebook-connect)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
