Frequently Asked Questions
Implement rate limiting with a library like express-rate-limit to prevent abuse of your /send-sms
endpoint, control costs, and enhance the stability of your service.
Use the Vonage Messages API and Node.js SDK. Set up an Express server, define an endpoint that accepts recipient number and message, then utilize the SDK to send the SMS via the API. This setup allows for sending messages programmatically.
The Vonage Messages API enables sending SMS messages programmatically from within applications. It handles the complexities of carrier integration so developers can easily add SMS functionality to projects like notifications or 2FA.
The private key, along with your Application ID, authenticates your application with the Vonage Messages API. It's crucial for security and should never be exposed publicly or committed to version control. Keep it safe and secure.
Whitelisting is mandatory for trial Vonage accounts. Add and verify the recipient number via the Vonage dashboard before sending test messages. This step is crucial to avoid "Non-Whitelisted Destination" errors.
Yes, Vonage provides a Node.js SDK (@vonage/server-sdk
) that simplifies interaction with both the Messages API (recommended) and the older SMS API. Ensure you are using the correct API and corresponding SDK methods, and check for any version compatibility.
Create a Vonage application, enable the Messages capability, generate and securely store your private key, link a Vonage virtual number, and configure these credentials as environment variables in your Express project. Use the @vonage/server-sdk
to interact with the API.
The dotenv
module loads environment variables from a .env
file into process.env
, making it easy to manage configuration like API keys, secrets, and other settings without hardcoding them in your application code.
Vonage has two SMS APIs. Setting the Default SMS API to "Messages API" in the Vonage dashboard ensures that the SDK uses the correct API, avoiding potential conflicts or unexpected behavior, especially with webhooks.
Implement try...catch
blocks around the vonage.messages.send()
call. Log error details, including any specific Vonage error information from the API response, to assist with debugging. Consider using a logging library for structured logs.
E.164 is an international telephone number format that includes the country code and number without any symbols or formatting (e.g., +15551234567 becomes 15551234567). It ensures consistent and accurate number handling for SMS delivery.
Never commit .env
or private key files to version control. Use platform-specific environment variable management in production. Consider storing the private key content as an environment variable directly for platforms like Heroku.
Use a platform like Heroku, AWS, or Google Cloud. Configure environment variables securely. Employ build processes if necessary, use a Procfile if required by the platform, and ensure all dependencies are installed correctly.
Double-check your Application ID, private key path, and the key file's content for accuracy. Verify correct file permissions. Ensure the Default SMS Setting in the Vonage dashboard is set to 'Messages API'.
MessageBird with Next.js and Supabase: OTP-Based Two-Factor Authentication
Introduction
Two-factor authentication (2FA) using One-Time Passwords (OTPs) adds an essential security layer to web applications by requiring users to verify their identity through a second factor – typically a verification code sent to their mobile device via SMS. This comprehensive guide demonstrates how to implement SMS-based OTP two-factor authentication in a Next.js application using MessageBird for reliable SMS delivery and Supabase for authentication and database storage.
What You'll Learn:
Prerequisites:
Project Overview
Architecture Flow:
Technologies:
1. Setting Up Your Next.js OTP Authentication Project
Initialize Next.js Project
Install Dependencies
Package Purposes:
messagebird
: Official MessageBird Node.js client for SMS API (npm)@supabase/supabase-js
: Supabase JavaScript client@supabase/ssr
: Server-side rendering authentication helpers for Next.jsConfigure Environment Variables
Create
.env.local
in project root:Get your credentials:
.env.local
to version controlUpdate
.gitignore
Ensure your
.gitignore
includes:2. Supabase Database Setup for OTP Storage
Create OTP Storage Table
Execute this SQL in Supabase SQL Editor:
Security Considerations:
3. MessageBird SMS API Configuration
Initialize MessageBird Client
Create
lib/messagebird.ts
:Important Notes:
4. Supabase Client Configuration for Next.js
Create
lib/supabase.ts
:5. Secure OTP Generation and Validation Logic
Create
lib/otp.ts
:Security Best Practices:
crypto.randomInt()
_ notMath.random()
(predictable)6. Next.js API Route: Send OTP via SMS
Create
app/api/send-otp/route.ts
:7. Next.js API Route: Verify OTP Code
Create
app/api/verify-otp/route.ts
:8. React Frontend Components for OTP Authentication
OTP Request Form
Create
components/OTPRequestForm.tsx
:OTP Verification Form
Create
components/OTPVerifyForm.tsx
:Main Page
Create
app/page.tsx
:9. Testing Your OTP Two-Factor Authentication
Development Server
Navigate to
http://localhost:3000
Test Flow
Request OTP:
+15551234567
Verify OTP:
Common Test Cases
Testing with MessageBird Trial
10. SMS OTP Security Best Practices and Vulnerabilities
Critical Security Measures Implemented
Crypto-Secure OTP Generation
crypto.randomInt()
instead ofMath.random()
Timing Attack Prevention
secureCompare()
Brute Force Protection
Rate Limiting
OTP Expiration
OTP Reuse Prevention
verified
flag prevents code reuseDatabase Security
Environment Variable Security
.env.local
(never committed)Additional Recommendations
HTTPS Only in Production
Audit Logging
Input Sanitization
SMS Message Security
Sources for Security Practices
11. Error Handling for MessageBird and Supabase
MessageBird Error Codes
MESSAGEBIRD_ACCESS_KEY
in.env.local
MessageBird API Error Reference
Supabase Error Handling
12. Deploying OTP Authentication to Production
Recommended Deployment: Vercel
Vercel is the recommended platform for Next.js applications with automatic optimizations.
Install Vercel CLI:
Deploy:
Configure Environment Variables:
.env.local
SUPABASE_SERVICE_ROLE_KEY
is only accessible server-sideProduction Considerations:
Alternative Platforms
Environment Variable Configuration
Ensure all required variables are set in production:
Post-Deployment Checklist
13. Troubleshooting Common OTP Issues
SMS OTP Not Received
Possible Causes:
Solutions:
+[country code][number]
"Invalid Access Key" Error
Cause: MessageBird access key incorrect or not set
Solution:
MESSAGEBIRD_ACCESS_KEY
in.env.local
matches.env.local
Supabase Connection Errors
Possible Causes:
Solutions:
supabaseAdmin
(service role) in API routesRate Limit Not Working
Cause: In-memory rate limiting doesn't work across serverless instances
Solution (Production):
Use Redis for distributed rate limiting:
OTP Expiration Not Working
Cause: Database timezone mismatch
Solution:
TIMESTAMP WITH TIME ZONE
)new Date(expires_at) < new Date()
14. Advanced OTP Features and Enhancements
Recommended Improvements
Email OTP Alternative
Resend OTP Functionality
Multi-Language Support
OTP Analytics Dashboard
Backup Authentication Methods
Advanced Rate Limiting
Improved UX
Web OTP API (Browser Autofill)
Modern browsers support auto-filling OTP from SMS:
SMS message must include:
@yourdomain.com #123456
Web OTP API Documentation
15. MessageBird and Supabase Resources
Official Documentation
Security Resources
Community and Support
Conclusion
You now have a complete, production-ready implementation of SMS-based OTP two-factor authentication using MessageBird for reliable SMS delivery, Next.js for the application framework, and Supabase for authentication and secure data storage.
Key Takeaways:
Remember:
This implementation provides a solid foundation for adding 2FA to any Next.js application. Customize the UI, add additional security layers, and extend functionality as needed for your specific use case.