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.
Top comments (0)