laravel-rebel-channel-twilio maintained by padosoft
Laravel Rebel — Twilio Channel
Send phone verifications through Twilio Verify, the Rebel way. This package plugs Twilio Verify (SMS / WhatsApp / voice) into
laravel-rebel-channelsas aVerificationProvider— so you get Twilio's global delivery plus Rebel's fraud guard, rate limiting, fallback and audit on top. Part of thepadosoft/laravel-rebel-*suite.
Table of contents
- What it is
- Quick glossary
- Why this package
- Rebel + Twilio vs the alternatives
- Twilio portal setup (step by step)
- Installation
- Configuration
- Usage
- Live tests against the real API
.env.example- Security notes
- Testing & License
What it is
A thin, well-tested Twilio Verify provider for Rebel Channels. You don't call it
directly — you call the Channels VerificationRouter, and it routes through this provider
(with Rebel's bot gate, IRSF defences, per-number rate limit, fallback and audit around it).
A small gateway seam (TwilioVerifyGateway) wraps the Twilio SDK, so the whole thing is
unit-testable offline and has a real live test-suite for the actual API.
Depends on padosoft/laravel-rebel-core
and padosoft/laravel-rebel-channels.
Quick glossary
| Term | In plain words |
|---|---|
| Twilio Verify | A Twilio product that sends and checks one-time codes for you — you never store or generate the OTP. |
| Verify Service | A Verify configuration (sender IDs, code length, channels). Identified by a SID starting with VA. |
| Account SID / Auth Token | Your Twilio account credentials (the SID starts with AC). |
| Channel | sms, whatsapp or voice (Twilio calls voice call). |
| Verification SID | The handle (VE...) for an in-flight verification. |
Why this package
| ★ | What | In short |
|---|---|---|
| ★★★ | Twilio Verify, fully wrapped | Start + check codes over SMS/WhatsApp/voice; you never handle the OTP yourself. |
| ★★★ | Rebel guarantees for free | Inherits the Channels fraud guard (IRSF), rate limit, fallback and HMAC'd audit. |
| ★★ | Never throws out | Any SDK/transport error becomes a clean provider_error, so the router can fall back to another provider. |
| ★★ | Offline-testable | A gateway seam + fake means your tests don't hit Twilio; a separate live suite does. |
| ★★ | Safe by default | No credentials → nothing registers, and no unauthenticated Twilio client is ever built. |
| ★ | Explicit status mapping | Twilio Verify statuses are mapped deliberately (an unexpected status is a failure, not a fake "pending"). |
Rebel + Twilio vs the alternatives
Sending an OTP with Twilio, three ways:
| Capability | Rebel + this package | Twilio Verify SDK (direct) | Raw Twilio SMS + your own OTP |
|---|---|---|---|
| Send/check a code via Twilio | ✅ | ✅ | ➖ (you build OTP logic) |
| You never store/generate the OTP | ✅ | ✅ | ❌ |
| Anti toll-fraud / IRSF guard | ✅ | ❌ | ❌ |
| Per-number rate limit + bot gate | ✅ | ❌ | ❌ |
| Provider fallback to another vendor | ✅ | ❌ | ❌ |
| Signed, phone-bound reference (anti replay) | ✅ | ❌ | ❌ |
| Unified audit trail (number HMAC'd) | ✅ | ❌ | ❌ |
| Graceful failure → router fallback | ✅ | ❌ | ❌ |
Legend: ✅ built-in · ➖ partial · ❌ not available. Twilio Verify is excellent at delivery; this package keeps all of that and adds the Rebel fraud/routing/audit layer around it.
Twilio portal setup (step by step)
- Create a Twilio account at twilio.com/try-twilio. The free trial gives you a small credit and a trial number — note that trial accounts can only send to verified caller IDs (add your test phone under Phone Numbers → Verified Caller IDs).
- Grab your credentials: on the Console home page copy your
Account SID (
AC...) and Auth Token. - Create a Verify Service: go to Verify → Services → Create new, give it a friendly
name (e.g. "MyApp Login"), choose the channels (SMS / WhatsApp / Voice), and copy the
Service SID (
VA...). - (WhatsApp only) enable the WhatsApp channel on the Verify Service and complete Twilio's WhatsApp sender onboarding.
- Put the three values in your
.env(see below). Done — the provider auto-registers.
Pricing: Twilio Verify is billed per successful verification + the channel cost; the free trial credit is enough to test end-to-end. Always keep the Rebel geo allowlist (in
laravel-rebel-channels) tight to avoid IRSF charges.
Installation
composer require padosoft/laravel-rebel-channel-twilio
php artisan vendor:publish --tag="rebel-channel-twilio-config"
Add your credentials to .env:
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_VERIFY_SERVICE_SID=VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
That's it — the provider registers itself into the Channels router under the key twilio.
Configuration
File config/rebel-channel-twilio.php:
| Key | Default | What it does |
|---|---|---|
account_sid |
env(TWILIO_ACCOUNT_SID) |
Twilio Account SID (AC...). |
auth_token |
env(TWILIO_AUTH_TOKEN) |
Twilio Auth Token. |
verify_service_sid |
env(TWILIO_VERIFY_SERVICE_SID) |
Verify Service SID (VA...). |
channels |
['sms','whatsapp','voice'] |
Which Rebel channels this provider may handle. |
register_provider |
true |
Auto-register into the Channels registry (when credentials exist). |
webhook.enabled |
false |
Enable a delivery-status callback endpoint. |
webhook.validate_signature |
true |
Validate X-Twilio-Signature on the webhook. |
webhook.path |
rebel/twilio/status |
The webhook route path. |
Usage
You typically don't touch this package directly — you use the Channels router:
use Padosoft\Rebel\Channels\Enums\Channel;
use Padosoft\Rebel\Channels\Routing\VerificationRouter;
use Padosoft\Rebel\Core\Context\SecurityContext;
use Padosoft\Rebel\Core\Identifiers\PhoneIdentifier;
$router = app(VerificationRouter::class);
// Send a code (Twilio Verify delivers it)
$start = $router->start(PhoneIdentifier::from('+39 333 1234567'), Channel::Sms, SecurityContext::fromRequest($request));
// Check what the user typed
$result = $router->check(PhoneIdentifier::from('+39 333 1234567'), $request->string('code'), $reference, SecurityContext::fromRequest($request));
if ($result->approved()) {
// verified!
}
To force Twilio specifically, set it first in the Channels fallback order:
// config/rebel-channels.php
'providers' => ['twilio'],
Live tests against the real API
The offline suite uses a fake gateway. To exercise the real Twilio Verify API
(tests/Live), opt in explicitly — it sends a real message:
# .env (or shell env)
REBEL_TWILIO_LIVE=1
TWILIO_TEST_PHONE=+39XXXXXXXXXX # a verified number on trial accounts
vendor/bin/pest --group=live
Without REBEL_TWILIO_LIVE=1 or with any credential missing, the live tests self-skip,
so composer test and external PRs never trigger a send. In CI, supply the values as
secrets and set REBEL_TWILIO_LIVE=1 on a dedicated job.
.env.example
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your_auth_token
TWILIO_VERIFY_SERVICE_SID=VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
REBEL_TWILIO_REGISTER=true
REBEL_TWILIO_WEBHOOK=false
REBEL_TWILIO_WEBHOOK_VALIDATE=true
REBEL_TWILIO_WEBHOOK_PATH=rebel/twilio/status
# Live tests (opt-in: SENDS A REAL MESSAGE)
REBEL_TWILIO_LIVE=0
TWILIO_TEST_PHONE=+391234567890
Security notes
- No unauthenticated client: the Twilio client is only constructed when all three credentials are present.
- No exception leakage: SDK/transport errors are caught and returned as a generic
provider_error— Twilio internals never bubble up to your app or logs. - Explicit status mapping: only Twilio's
pendingis treated as a live challenge; any unexpected status fails closed. - Keep IRSF defences on: pair this with the Channels geo allowlist / per-prefix cap to avoid premium-rate fraud charges.
Testing & License
composer test # Pest (provider + Channels integration; live suite self-skips)
composer phpstan # static analysis, level max
composer pint # code style
License: MIT — see LICENSE. Part of the padosoft/laravel-rebel suite.