SMS has long been the default channel for One-Time Password (OTP) verification and two-factor authentication (2FA). However, SMS OTP delivery faces major systemic challenges today:
- High Delivery Failure Rates: Telecom carrier filtering, SS7 vulnerabilities, and SIM-swap attacks.
- High Latency: SMS OTPs frequently take 60 to 180 seconds to arrive in international regions, causing user registration abandonment.
- Rising Carrier Costs: International A2P SMS rates continue to escalate globally.
By switching your authentication pipeline to WhatsApp Business Cloud API, OTPs arrive via encrypted push notifications in under 5 seconds with a 99.8% delivery success rate.
In this guide, we walk through building a resilient WhatsApp OTP authentication microservice using Node.js, Redis, and Meta's official Authentication template API.
Understanding Meta's Authentication Template Rules
Meta enforces strict security policies for Authentication conversations:
- Templates must contain only an alphanumeric verification code and an optional one-tap autofill button (
COPY_CODEorONE_TAP). - URLs, images, media, and marketing text are strictly prohibited within Authentication templates.
- Pricing is significantly discounted: Meta prices Authentication conversations substantially lower than marketing broadcasts (see exact regional pricing in the Meta Per-Message Cost Guide).
Step 1: Generating and Storing the OTP in Redis
import crypto from "crypto"; import Redis from "ioredis"; const redis = new Redis(process.env.REDIS_URL); export async function generateOtp(phoneNumber) { // Generate a cryptographically secure 6-digit numeric code const code = crypto.randomInt(100000, 999999).toString(); // Store in Redis with a 5-minute (300 seconds) expiration window const otpKey = `otp:${phoneNumber}`; await redis.set(otpKey, code, "EX", 300); return code; } Step 2: Dispatching the WhatsApp Authentication Template
When sending an OTP, use Meta's standardized authentication template payload:
import axios from "axios"; export async function sendWhatsAppOtp(recipientPhone, otpCode) { const url = `https://graph.facebook.com/v21.0/${process.env.WHATSAPP_PHONE_ID}/messages`; const payload = { messaging_product: "whatsapp", recipient_type: "individual", to: recipientPhone, type: "template", template: { name: "auth_otp_code", language: { code: "en_US" }, components: [ { type: "body", parameters: [ { type: "text", text: otpCode } // Injects OTP into the template body ] }, { type: "button", sub_type: "url", index: "0", parameters: [ { type: "text", text: otpCode } // Enables 1-tap "Copy Code" button ] } ] } }; const response = await axios.post(url, payload, { headers: { Authorization: `Bearer ${process.env.WHATSAPP_ACCESS_TOKEN}`, "Content-Type": "application/json" } }); return response.data; } Step 3: Verifying the User's Submitted Code
export async function verifyOtp(phoneNumber, submittedCode) { const otpKey = `otp:${phoneNumber}`; const storedCode = await redis.get(otpKey); if (!storedCode) { return { success: false, message: "OTP has expired or does not exist." }; } // Constant-time string comparison to prevent timing attacks const isValid = crypto.timingSafeEqual(Buffer.from(storedCode), Buffer.from(submittedCode)); if (isValid) { // Delete immediately after successful verification (single-use token) await redis.del(otpKey); return { success: true, message: "Phone number verified successfully!" }; } return { success: false, message: "Invalid verification code." }; } Enterprise Authentication with AI Soul
If you don't want to manage WhatsApp template approvals, Redis clusters, and carrier delivery status callbacks manually, modern platforms like AI Soul provide a complete messaging layer.
AI Soul connects directly to Meta Cloud API, enabling automated WhatsApp Drip Campaigns, transactional order alerts, and customer notifications with 0% platform markup on Meta's base message rates.
Summary Checklist
- [x] Use cryptographically secure numeric generation (
crypto.randomInt). - [x] Expire OTPs in Redis after 3 to 5 minutes.
- [x] Invalidate tokens immediately upon verification.
- [x] Include a one-tap "Copy Code" button to maximize mobile login conversion.
