Skip to content

199-biotechnologies/twilio-otp-framework

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Twilio OTP Framework

Production-grade phone verification for Next.js — SMS, voice calls, WhatsApp, fraud prevention, and everything in between.


Star this repo    Follow @longevityboris


License: MIT   TypeScript   Next.js   PRs Welcome


Every project eventually needs phone verification. You search "Twilio OTP," find a blog post from 2019, copy-paste some code, ship it, and hope nobody finds the holes you left open. No rate limiting. No brute force protection. No fraud prevention. Plain-text codes sitting in your database.

This framework is what we wish existed when we built phone auth for Healtrix and Petus AI. Battle-tested patterns extracted from production, documented so an AI agent (or a human) can implement OTP correctly on the first try.

Architecture | What's Inside | Quick Start | Features | Docs | Contributing

The Problem

Most OTP implementations are dangerously incomplete:

What most tutorials ship What production actually needs
Plain SHA256 hash (brute-forced in seconds) HMAC-SHA256 with server secret
No rate limiting Per-phone + per-IP + fail-closed when Redis is down
SMS only, no fallback SMS → Voice call → WhatsApp escalation
Math.random() for code generation crypto.randomInt() (CSPRNG)
OTP stored until expiry Atomic single-use deletion
No fraud prevention Twilio Lookup v2 + SMS pumping risk scores
No delivery tracking Webhook validation + status callbacks
Phone stored as-is E.164 normalization with libphonenumber-js

Architecture

┌─────────────────────────────────────────────────────────┐
│                       CLIENT                             │
│  Phone Input (E.164) → OTP Input (6-digit) → Session    │
└────────────────────────┬────────────────────────────────┘
                         │
┌────────────────────────▼────────────────────────────────┐
│                     API LAYER                            │
│                                                          │
│  POST /api/otp/send ──── Rate limit → Lookup → Hash     │
│                          → Store → Send (SMS/Voice/WA)   │
│                                                          │
│  POST /api/otp/verify ── Rate limit → Brute force check  │
│                          → Timing-safe compare            │
│                          → Atomic delete → Session        │
│                                                          │
│  POST /api/otp/resend ── Channel escalation              │
│                          (SMS → SMS → Voice)              │
│                                                          │
│  POST /api/twilio/webhook ── Signature validation        │
│                              → Delivery tracking          │
└───────┬──────────┬──────────┬───────────────────────────┘
        │          │          │
   PostgreSQL    Redis     Twilio
   (OTPs, users, (Rate    (SMS, Voice,
    sessions,    limits)   WhatsApp,
    audit log)             Verify, Lookup)

What's Inside

twilio-otp-framework/
├── src/
│   ├── components/
│   │   ├── PhoneInput.tsx        # International phone input with flags
│   │   ├── OtpInput.tsx          # 6-digit code with paste + auto-advance
│   │   ├── VerificationFlow.tsx  # Complete phone → OTP → verified flow
│   │   ├── LoginWithPhone.tsx    # Dual-mode login box (Email / Phone)
│   │   └── index.ts             # Barrel export
│   ├── lib/
│   │   ├── otp.ts               # Generation + HMAC-SHA256 hashing
│   │   ├── sms.ts               # Twilio SMS (direct REST, no SDK)
│   │   ├── voice.ts             # Voice call OTP fallback
│   │   ├── whatsapp.ts          # WhatsApp OTP channel
│   │   ├── twilio-verify.ts     # Twilio Verify API (managed alternative)
│   │   ├── rate-limit.ts        # Multi-tier: Redis + in-memory + fail-closed
│   │   ├── phone.ts             # E.164 normalization + validation
│   │   ├── webhook.ts           # Twilio signature validation
│   │   ├── session.ts           # DB-backed sessions + HTTP-only cookies
│   │   ├── security.ts          # Timing guards, phone intelligence, geo-blocking
│   │   └── audit.ts             # Fire-and-forget event logging
│   ├── api/
│   │   ├── send-otp/route.ts    # Send OTP endpoint
│   │   ├── verify-otp/route.ts  # Verify OTP endpoint
│   │   ├── resend-otp/route.ts  # Resend with channel escalation
│   │   └── twilio-webhook/      # Delivery status callbacks
│   └── db/
│       └── schema.sql           # Complete PostgreSQL schema
├── docs/                        # 16 in-depth guides (see below)
├── .env.example                 # All env vars documented
├── SECURITY.md                  # Vulnerability reporting
└── LICENSE                      # MIT

Quick Start

1. Clone and explore

git clone https://github.com/199-biotechnologies/twilio-otp-framework.git
cd twilio-otp-framework

2. Copy the modules you need into your Next.js project

# Copy the core OTP library
cp src/lib/otp.ts your-project/lib/
cp src/lib/sms.ts your-project/lib/
cp src/lib/rate-limit.ts your-project/lib/
cp src/lib/phone.ts your-project/lib/

# Copy the API routes (rename directories to match your routing)
cp src/api/send-otp/route.ts your-project/app/api/otp/send/route.ts
cp src/api/verify-otp/route.ts your-project/app/api/otp/verify/route.ts
cp src/api/resend-otp/route.ts your-project/app/api/otp/resend/route.ts

3. Set up your database

psql $DATABASE_URL < src/db/schema.sql

4. Configure environment

cp .env.example .env.local
# Fill in your Twilio credentials, OTP_HMAC_SECRET, and database URL

This is a reference framework, not a runnable app or npm package. The library code is copy-paste ready, but SQL queries are commented out with // await sql — you need to adapt them to your ORM (Drizzle, Prisma, raw SQL). The patterns, security decisions, and architecture are production-tested; the wiring is yours to do.

Features

Delivery Channels

Channel File When to Use
SMS sms.ts Default for all users
Voice Call voice.ts SMS delivery fails, user requests call, landline detected
WhatsApp whatsapp.ts User preference, cheaper in LATAM/India/Europe
Twilio Verify twilio-verify.ts Managed OTP — Twilio handles everything

Security Stack

Layer Protection Details
Hashing HMAC-SHA256 with server secret DB breach doesn't expose valid codes
Brute Force 5 attempts per OTP Code invalidated after max attempts
Rate Limiting Per-phone (3/10min) + per-IP (10/10min) Fail-closed when Redis is down
Timing Safety crypto.timingSafeEqual + response padding Prevents enumeration via timing
Single Use Atomic DELETE on verification No replay attacks
Phone Intelligence Twilio Lookup v2 Block VoIP, detect SMS pumping, SIM swap
Fraud Guard Twilio Verify built-in Blocks known pumping patterns
Geo Permissions Country whitelist Only send to countries you serve

Phone Management

  • E.164 normalization"07700 900000""+447700900000"
  • Duplicate protection — partial unique indexes for active accounts
  • Phone verification claims — server-side proof of ownership for registration
  • Alpha Sender IDs — branded SMS ("HEALTRIX" instead of a phone number)
  • A2P 10DLC compliance — US carrier registration guide

Ready-to-Use UI Components (src/components/)

Four React components you can drop into any Next.js project:

Component What It Does
PhoneInput International input with country flags, E.164 output, validation
OtpInput 6-digit code with auto-advance, paste support, autocomplete="one-time-code" for browser SMS auto-fill
VerificationFlow Complete phone → send code → enter code → verified. Resend timer, channel escalation, "Call me instead"
LoginWithPhone Dual-mode login box (Email magic link / Phone OTP) with tab switcher. Plug in your endpoints and go.
// One component, entire verification flow
<VerificationFlow
  onVerified={(phone) => router.push("/dashboard")}
  defaultCountry="GB"
  appName="Healtrix"
/>

// Or the full login box with email + phone tabs
<LoginWithPhone
  onAuthenticated={(result) => handleLogin(result)}
  modes={["phone", "email"]}
  brandName="Sign in to Healtrix"
  brandLogo="/logo.svg"
/>

All components use Tailwind CSS classes. Swap the classes for your design system.

Documentation

Every doc is self-contained with code snippets you can copy directly:

# Guide What You'll Learn
01 Architecture System design, security layers, Custom vs Verify decision
02 Sending OTP SMS, Voice, WhatsApp, Alpha Sender, REST vs SDK
03 Verification Login flow, registration claims, phone linking, atomic ops
04 Rate Limiting Multi-tier limits, Redis + in-memory, fail-closed
05 Security & Hardening HMAC hashing, timing attacks, fraud prevention, SMS pumping
06 Phone Management E.164, normalization, linking patterns, duplicate protection
07 Retry & Fallback Channel escalation, webhook-driven fallback, backoff
08 Twilio Verify API Managed OTP, SNA, Passkeys, Fraud Guard, pricing
09 Webhooks Signature validation, delivery tracking, error codes
10 Session Management DB-backed sessions, sliding window, cookie security
11 Frontend Patterns Phone input, OTP input, verification flow components
12 Monitoring & Audit Event logging, conversion tracking, alerting
13 Launch Checklist Pre-production security review
14 Integrations Supabase Auth, NextAuth, better-auth, Stripe
15 Testing Test credentials, mocking, webhook fixtures, E2E
16 Privacy & Compliance GDPR, data retention, encryption, Twilio as processor

Custom OTP vs Twilio Verify

Both approaches are fully documented. Here's how to choose:

Custom OTP (this repo) Twilio Verify
You control Everything Channel + Fraud Guard level
OTP storage Your database (hashed) Twilio's infrastructure
Rate limiting You build it Built-in
Fraud prevention Lookup v2 + your logic Fraud Guard (saved $62.7M for customers)
Channels Whatever you build SMS, Voice, WhatsApp, Email, SNA, Push, TOTP, Passkeys
Cost ~$0.008/SMS (US) $0.05/verification + channel fee
Best for Full control, complex flows, cost at scale Fast MVP, multi-channel, built-in fraud protection

Our recommendation: Start with Twilio Verify for speed. Switch to custom when you need phone verification claims or tighter cost control at scale.

For AI Agents

This repo is designed to be read by AI coding agents. When pointing an agent at this framework:

Reference https://github.com/199-biotechnologies/twilio-otp-framework
for implementing phone OTP authentication. Use the patterns from
src/lib/ for the core logic and docs/ for security requirements.

Every file has clear JSDoc comments explaining why each decision was made. The docs cover edge cases and mistakes that will bite you in production.

Contributing

Found a gap? Have a better pattern? PRs are welcome.

  1. Fork the repo
  2. Make your changes
  3. Open a PR with context on what you improved and why

See CONTRIBUTING.md for details.

License

MIT — use this however you want.


Built by Boris Djordjevic at 199 Biotechnologies | Paperfoot AI


If this saves you time:

Star this repo    Follow @longevityboris