aslnbxrz / simple-otp
A simple and flexible OTP (One-Time Password) management package for Laravel with multiple storage drivers and delivery methods
Installs: 4
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/aslnbxrz/simple-otp
Requires
- php: ^8.1
- illuminate/cache: ^10.0|^11.0|^12.0
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/mail: ^10.0|^11.0|^12.0
- illuminate/notifications: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- mockery/mockery: ^1.4
- orchestra/testbench: ^8.0
- phpunit/phpunit: ^10.0
README
A simple, flexible, and production-ready OTP (One-Time Password) management package for Laravel applications. This package provides multiple storage drivers (Cache, Database, Redis) and delivery methods (SMS, Email, Log) with comprehensive configuration options.
Features
- ๐ Multiple Storage Drivers: Cache, Database, Redis
- ๐ฑ Multiple Delivery Methods: SMS (Twilio, Nexmo), Email, Log
- โก High Performance: Optimized for production use
- ๐ Security Features: Rate limiting, attempt tracking, automatic cleanup
- ๐จ Flexible Configuration: Customizable code types, lengths, TTL, and messages
- ๐งช Well Tested: Comprehensive test coverage
- ๐ฆ Laravel Integration: Service provider, facades, and artisan commands
Installation
Via Composer
composer require aslnbxrz/simple-otp
Publish Configuration
php artisan vendor:publish --provider="Aslnbxrz\\SimpleOTP\\SimpleOTPServiceProvider" --tag="simple-otp-config"
Publish Migrations (for database storage)
php artisan vendor:publish --provider="Aslnbxrz\\SimpleOTP\\SimpleOTPServiceProvider" --tag="simple-otp-migrations" php artisan migrate
Publish Email Views (optional)
php artisan vendor:publish --provider="Aslnbxrz\\SimpleOTP\\SimpleOTPServiceProvider" --tag="simple-otp-views"
Configuration
The package configuration file will be published to config/simple-otp.php. Here's an overview of the main configuration options:
Storage Configuration
// config/simple-otp.php return [ 'default' => env('SIMPLE_OTP_STORAGE', 'cache'), 'drivers' => [ 'cache' => [ 'driver' => 'cache', 'store' => env('SIMPLE_OTP_CACHE_STORE', null), // null means use default cache store ], 'database' => [ 'driver' => 'database', 'table' => 'simple_otp_codes', 'connection' => env('SIMPLE_OTP_DB_CONNECTION', null), ], 'redis' => [ 'driver' => 'redis', 'connection' => env('SIMPLE_OTP_REDIS_CONNECTION', 'default'), 'prefix' => env('SIMPLE_OTP_REDIS_PREFIX', 'simple_otp:'), ], ], ];
Delivery Configuration
'delivery' => [ 'default' => env('SIMPLE_OTP_DELIVERY', 'log'), 'drivers' => [ 'sms' => [ 'driver' => 'sms', 'provider' => env('SIMPLE_OTP_SMS_PROVIDER', 'twilio'), 'config' => [ 'twilio' => [ 'account_sid' => env('TWILIO_ACCOUNT_SID'), 'auth_token' => env('TWILIO_AUTH_TOKEN'), 'from' => env('TWILIO_FROM_NUMBER'), ], 'nexmo' => [ 'api_key' => env('NEXMO_API_KEY'), 'api_secret' => env('NEXMO_API_SECRET'), 'from' => env('NEXMO_FROM_NUMBER'), ], 'eskiz' => [ 'email' => env('ESKIZ_EMAIL'), 'password' => env('ESKIZ_PASSWORD'), 'from' => env('ESKIZ_FROM', '4546'), 'base_url' => env('ESKIZ_BASE_URL', 'https://notify.eskiz.uz/api'), ], 'telegram' => [ 'bot_token' => env('TELEGRAM_BOT_TOKEN'), 'parse_mode' => env('TELEGRAM_PARSE_MODE', 'HTML'), 'disable_web_page_preview' => env('TELEGRAM_DISABLE_PREVIEW', true), ], ], ], 'email' => [ 'driver' => 'email', 'mailable' => \Aslnbxrz\SimpleOTP\Mail\OTPMailable::class, 'from' => [ 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), 'name' => env('MAIL_FROM_NAME', 'Example'), ], ], ], ],
OTP Configuration
'otp' => [ 'type' => env('SIMPLE_OTP_TYPE', 'numeric'), // numeric, alphanumeric, alpha 'length' => (int) env('SIMPLE_OTP_LENGTH', 6), 'ttl' => (int) env('SIMPLE_OTP_TTL', 5), // minutes 'max_attempts' => (int) env('SIMPLE_OTP_MAX_ATTEMPTS', 3), 'rate_limit' => [ 'enabled' => env('SIMPLE_OTP_RATE_LIMIT_ENABLED', true), 'max_attempts' => (int) env('SIMPLE_OTP_RATE_LIMIT_ATTEMPTS', 5), 'decay_minutes' => (int) env('SIMPLE_OTP_RATE_LIMIT_DECAY', 60), ], ],
Environment Variables
Add these variables to your .env file:
# Storage Configuration SIMPLE_OTP_STORAGE=cache SIMPLE_OTP_CACHE_STORE=null SIMPLE_OTP_DB_CONNECTION=mysql SIMPLE_OTP_REDIS_CONNECTION=default SIMPLE_OTP_REDIS_PREFIX=simple_otp: # Delivery Configuration SIMPLE_OTP_DELIVERY=log SIMPLE_OTP_SMS_PROVIDER=twilio # Twilio Configuration TWILIO_ACCOUNT_SID=your_account_sid TWILIO_AUTH_TOKEN=your_auth_token TWILIO_FROM_NUMBER=+1234567890 # Nexmo Configuration (alternative) NEXMO_API_KEY=your_api_key NEXMO_API_SECRET=your_api_secret NEXMO_FROM_NUMBER=1234567890 # Eskiz Configuration (Uzbekistan) ESKIZ_EMAIL=your_email ESKIZ_PASSWORD=your_password ESKIZ_FROM=4546 ESKIZ_BASE_URL=https://notify.eskiz.uz/api # Telegram Configuration TELEGRAM_BOT_TOKEN=your_bot_token TELEGRAM_PARSE_MODE=HTML TELEGRAM_DISABLE_PREVIEW=true # OTP Configuration SIMPLE_OTP_TYPE=numeric SIMPLE_OTP_LENGTH=6 SIMPLE_OTP_TTL=5 SIMPLE_OTP_MAX_ATTEMPTS=3 SIMPLE_OTP_RATE_LIMIT_ENABLED=true SIMPLE_OTP_RATE_LIMIT_ATTEMPTS=5 SIMPLE_OTP_RATE_LIMIT_DECAY=60
Usage
Basic Usage with Facade
use Aslnbxrz\SimpleOTP\Facades\SimpleOTP; // Generate and send OTP $result = SimpleOTP::generate('user-123', 'user@example.com'); // Returns: ['success' => true, 'message' => 'OTP code has been sent successfully.', ...] // Verify OTP $verified = SimpleOTP::verify('user-123', '123456'); // Returns: true or throws OTPException // Check if OTP exists $exists = SimpleOTP::exists('user-123'); // Returns: true/false // Get OTP information $info = SimpleOTP::info('user-123'); // Returns: ['identifier' => 'user-123', 'recipient' => 'user@example.com', ...] // Resend OTP $result = SimpleOTP::resend('user-123', 'user@example.com'); // Delete OTP $deleted = SimpleOTP::delete('user-123');
Usage in Controllers
<?php namespace App\Http\Controllers; use Aslnbxrz\SimpleOTP\Facades\SimpleOTP; use Aslnbxrz\SimpleOTP\Exceptions\OTPException; use Illuminate\Http\Request; class AuthController extends Controller { public function sendOTP(Request $request) { try { $identifier = 'user-' . $request->user()->id; $recipient = $request->user()->phone; // or email $result = SimpleOTP::generate($identifier, $recipient); return response()->json([ 'success' => true, 'message' => $result['message'], 'expires_at' => $result['expires_at'], ]); } catch (OTPException $e) { return response()->json([ 'success' => false, 'message' => $e->getMessage(), ], 400); } } public function verifyOTP(Request $request) { try { $identifier = 'user-' . $request->user()->id; $code = $request->input('code'); $verified = SimpleOTP::verify($identifier, $code); if ($verified) { // Mark user as verified or perform other actions $request->user()->markAsVerified(); return response()->json([ 'success' => true, 'message' => 'Phone number verified successfully.', ]); } } catch (OTPException $e) { return response()->json([ 'success' => false, 'message' => $e->getMessage(), ], 400); } } }
Custom SMS/Email Messages
// Custom SMS message $result = SimpleOTP::generate('user-123', '+1234567890', [ 'message' => 'Your verification code for MyApp is: {code}' ]); // Custom email subject and message $result = SimpleOTP::generate('user-123', 'user@example.com', [ 'subject' => 'Verify Your Account', 'message' => 'Please use the following code to verify your account: {code}' ]);
Storage Drivers
Cache Storage (Default)
- Uses Laravel's cache system
- Automatic expiration
- High performance
- Suitable for most applications
Database Storage
- Persistent storage
- Better for distributed applications
- Requires migration
- Automatic cleanup available
Redis Storage
- High performance
- Distributed caching
- Automatic expiration
- Best for high-traffic applications
Delivery Drivers
SMS Driver
Currently supports:
- Twilio: Popular SMS service provider
- Nexmo (Vonage): International SMS service
- Eskiz: Uzbekistan SMS service provider (using native cURL)
- Telegram: Telegram Bot API for instant messaging
Email Driver
- Uses Laravel's mail system
- Customizable templates
- HTML and text versions
Log Driver
- For development and testing
- Logs OTP codes to Laravel logs
- No external dependencies
Advanced Features
Rate Limiting
The package includes built-in rate limiting to prevent abuse:
'rate_limit' => [ 'enabled' => true, 'max_attempts' => 5, // Max OTP requests per time window 'decay_minutes' => 60, // Time window in minutes ],
Custom Code Types
Generate different types of OTP codes:
// Numeric (default): 123456 'type' => 'numeric' // Alphanumeric: A1B2C3 'type' => 'alphanumeric' // Alpha only: ABCDEF 'type' => 'alpha'
Automatic Cleanup
Expired OTP codes are automatically cleaned up based on configuration:
'cleanup' => [ 'enabled' => true, 'interval_hours' => 24, // Run cleanup every 24 hours ],
Testing
The package includes comprehensive tests. To run them:
composer test
Error Handling
The package throws specific exceptions that you can catch and handle:
use Aslnbxrz\SimpleOTP\Exceptions\OTPException; use Aslnbxrz\SimpleOTP\Exceptions\OTPDeliveryException; try { SimpleOTP::generate('user-123', 'user@example.com'); } catch (OTPDeliveryException $e) { // Handle delivery failure (SMS/Email service down, etc.) Log::error('OTP delivery failed: ' . $e->getMessage()); } catch (OTPException $e) { // Handle other OTP-related errors Log::error('OTP error: ' . $e->getMessage()); }
Security Considerations
- Rate Limiting: Always enable rate limiting in production
- TTL: Use appropriate TTL values (5-10 minutes recommended)
- Max Attempts: Limit verification attempts (3-5 recommended)
- Storage: Use Redis or Database for production (not cache)
- HTTPS: Always use HTTPS in production
- Cleanup: Enable automatic cleanup of expired codes
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for your changes
- Run the test suite
- Submit a pull request
License
This package is open-sourced software licensed under the MIT license.
Support
For support, please open an issue on the GitHub repository.
Changelog
v1.0.0
- Initial release
- Multiple storage drivers (Cache, Database, Redis)
- Multiple delivery methods (SMS, Email, Log)
- Rate limiting and security features
- Comprehensive test coverage
- Laravel integration with facades and service providers