Frequently Asked Questions
To send an OTP SMS, create a Next.js API route that uses the Plivo Node.js SDK to call the Plivo Verify API's `client.verify.session.create()` method. This API route should handle the request containing the user's phone number and make the API call to Plivo. It needs to send the recipient's phone number and specify 'sms' as the channel. The API route should also return the `session_uuid` to the client for later verification.
First install the Plivo Node.js SDK (`npm install plivo`). Then, set up environment variables (`PLIVO_AUTH_ID`, `PLIVO_AUTH_TOKEN`) in `.env.local`. Create API routes in Next.js (e.g., `/api/otp/send` and `/api/otp/verify`) to handle the Plivo Verify API interaction. Initialize the Plivo client in your API routes using your environment variables to make calls to the Plivo Verify API.
The Plivo Verify API is used for sending and validating One-Time Passwords (OTPs) for various purposes like Two-Factor Authentication (2FA) and phone number verification during user signup. It supports sending OTPs via SMS, Voice, and WhatsApp.
Create an API route (e.g., `/api/otp/verify`) that receives the `session_uuid` (from sending the OTP) and the user-entered OTP. Use the Plivo SDK's `client.verify.session.validate()` method to check if the OTP is valid, matching it against the `session_uuid`. Return a success/failure response to the frontend based on Plivo's response. Ensure you check the Plivo documentation for robust validation indicators (status codes or flags).
Plivo offers several benefits for OTP verification including: a simple API, global coverage, high delivery rates for SMS messages, competitive pricing, and built-in fraud protection features (like Fraud Shield), making it a reliable choice for enhancing security.
Two API routes are typically used: `/api/otp/send` to send the OTP via the Plivo Verify API, and `/api/otp/verify` to check the user-entered OTP against the Plivo Verify API using the `session_uuid`.
Obtain your `AUTH_ID` and `AUTH_TOKEN` from the Plivo console under API Keys & Credentials. Store these values as environment variables in a `.env.local` file in your project's root directory. Next.js loads environment variables from this file for local development. Never commit `.env.local` to version control.
You will need Node.js and npm/yarn, a Plivo account (sign up at plivo.com), a basic understanding of React and Next.js components, API routes, hooks, and access to a terminal.
Rate limiting is crucial for security and to prevent abuse, such as preventing attackers from spamming phone numbers or brute-forcing OTPs. It should be implemented from the start, especially in production environments. Limit OTP requests and verification attempts based on IP, user ID, or phone number.
Implement `try...catch` blocks in both API routes and frontend code. Log detailed error messages server-side for debugging and provide user-friendly feedback in the frontend UI. You can also add retries for specific error scenarios, such as network issues during API calls to Plivo.
The article recommends using Node.js version 18 or later when setting up a Next.js project with Plivo OTP integration for optimal compatibility.
While the example uses basic regex, consider using a dedicated library like `react-phone-number-input` on the client-side and a robust server-side library (e.g., Google's `libphonenumber`) for thorough format checking, especially if handling international numbers.
The example doesn't explicitly include a resend feature, but you can implement it by adding a "Resend OTP" button to the UI. This button should call the same `/api/otp/send` API route again. Add a cooldown period to prevent abuse, typically by disabling the button for a short period after each click.
Although not shown in the article, in a real app, integrate OTP verification with your user database. Store user phone numbers (in E.164 format), and a verification flag (`is_phone_verified`). After successful OTP verification, update this flag in your database.
This guide provides a step-by-step walkthrough for integrating Plivo's Verify API into a Next.js application to implement robust One-Time Password (OTP) verification, often used for Two-Factor Authentication (2FA) or phone number validation during sign-up.
We will build a simple Next.js application featuring:
This implementation solves the critical need for verifying user phone numbers, enhancing security against fake accounts and unauthorized access, while leveraging Plivo's global reach, high deliverability, and built-in fraud protection.
Technologies Used:
Prerequisites:
System Architecture:
The typical flow involves the user's browser interacting with Next.js API routes, which in turn communicate with the Plivo Verify API to send an OTP via SMS to the user's phone and later validate the OTP entered by the user.
Final Outcome:
By the end of this guide, you will have a functional Next.js page where a user can enter their phone number, receive an OTP via SMS managed by Plivo, enter that OTP, and have it validated, with UI feedback indicating success or failure. You will also understand how to securely handle API credentials, implement basic error handling, and consider security measures like rate limiting.
1. Setting Up the Project
Let's start by creating a new Next.js project and installing the necessary dependencies.
Create a Next.js App: Open your terminal and run the following command. Replace
plivo-nextjs-otp
with your preferred project name. Follow the prompts (we recommend using TypeScript and App Router if prompted, but this guide uses Pages Router for simplicity in API routes).Install Plivo Node.js SDK: This package provides convenient methods for interacting with the Plivo API.
Set Up Environment Variables: Sensitive information like API keys should never be hardcoded. We'll use environment variables.
Create a file named
.env.local
in the root of your project.Add the following lines, replacing the placeholder values later:
Important: Add
.env.local
to your.gitignore
file (it should be there by default in Next.js projects) to prevent accidentally committing your secrets.Why
.env.local
? Next.js automatically loads variables from this file for local development. For production deployment, you'll need to configure these environment variables directly in your hosting provider's settings (e.g., Vercel, Netlify).Project Structure: Your basic structure (using Pages Router) will look like this:
Run the Development Server: Verify the basic setup is working.
Open your browser to
http://localhost:3000
. You should see the default Next.js welcome page.2. Implementing Core Functionality (API Layer)
Now, we'll build the backend API routes within Next.js to handle sending and verifying OTPs using the Plivo SDK.
2.1 API Route to Send OTP (
/api/otp/send
)This endpoint will receive a phone number, initiate the Plivo Verify session, and return the
session_uuid
to the client.Create the file:
pages/api/otp/send.js
Add the following code:
Explanation:
Client
.POST
requests.recipient
phone number from the request body. Basic validation is included.client.verify.session.create()
is called with the recipient number andchannel: 'sms'
. This tells Plivo to generate an OTP and send it via SMS.sessionUuid
. We extract and send this back to the client in the JSON response.try...catch
block. We log the detailed error server-side and return a generic error message to the client.2.2 API Route to Verify OTP (
/api/otp/verify
)This endpoint receives the
session_uuid
(obtained from the previous step) and theotp
entered by the user, then validates them with Plivo.Create the file:
pages/api/otp/verify.js
Add the following code:
Explanation:
POST
method check.session_uuid
andotp
from the request body. Includes validation for presence and basic OTP format./^\d{6}$/
) and frontend accordingly.client.verify.session.validate()
is called with thesession_uuid
and theotp
.{ verified: false }
.catch
block handles API communication errors or unexpected Plivo errors during validation, logging details server-side and returning appropriate client-side messages (e.g., specific messages for 404 or 400 errors).3. Building the Frontend UI
Now let's create the React component for the user interface on the main page.
Edit the main page:
pages/index.js
Replace its content with the following:
Explanation:
useState
hooks to manage the phone number input, OTP input, session UUID, loading state, UI messages, errors, and whether the OTP form should be visible (isOtpSent
), and verification status (isVerified
).OTP_LENGTH
constant is defined (defaulting to 6) for easier adjustment and used in validation and input attributes.handleSendOtp
:react-phone-number-input
for robust international phone number validation in production.POST
request to/api/otp/send
with the phone number.session_uuid
, shows a success message, and setsisOtpSent
to true to display the OTP input form.handleVerifyOtp
:OTP_LENGTH
constant.POST
request to/api/otp/verify
with thesession_uuid
andotp
.data.verified
is true, shows a success message and setsisVerified
. Otherwise, throws an error.isOtpSent
andisVerified
. InputmaxLength
,pattern
, and validation logic now use theOTP_LENGTH
constant.4. Integrating with Plivo (Credentials)
You've already set up the environment variables, but let's ensure you know where to find the Plivo credentials.
Log in to your Plivo Console: Go to console.plivo.com.
Navigate to API Keys: On the main dashboard or via the navigation menu, find the section related to ""API"" or ""Account"" and look for ""Keys & Credentials"" or similar.
Copy Auth ID and Auth Token: You will see your
AUTH ID
andAUTH TOKEN
. Copy these values.Update
.env.local
: Paste the copied values into your.env.local
file:CRITICAL: You must replace the placeholder text above with your actual credentials obtained from the Plivo console for the application to function.
Restart your Next.js server: Environment variables in
.env.local
are only loaded at build time or server start. Stop your development server (Ctrl+C) and restart it:Secure Handling:
.env.local
or your actual credentials to version control (Git).5. Error Handling, Logging, and Retries
We've added basic error handling, but let's refine it.
console.log
andconsole.error
in the API routes. For production, use a structured logging library likepino
orwinston
. This enables better log parsing, filtering, and integration with log management services (e.g., Datadog, Logtail)./api/otp/send
endpoint again. Implement a cooldown period (e.g., disable the button for 30-60 seconds after a request) to prevent abuse.async-retry
). However, for OTP, be cautious: retrying acreate
call might result in multiple OTPs being sent (and billed). Retrying avalidate
call is generally safer if the initial attempt failed due to a network issue. Start simple; add server-side retries only if transient Plivo API call failures become a noticeable problem.Testing Error Scenarios:
.env.local
to simulate auth errors.6. Database Schema and Data Layer (Considerations)
This specific guide focuses solely on OTP verification and doesn't implement a full user database. However, in a production application, you would integrate this flow with your user management system:
id
email
/username
password_hash
phone_number
(string, store in E.164 format)is_phone_verified
(boolean, defaults tofalse
)two_factor_enabled
(boolean, defaults tofalse
)created_at
,updated_at
is_phone_verified = true
for the newly created user record.two_factor_enabled = true
, prompt for OTP -> Send OTP (using the user's verifiedphone_number
) -> Verify OTP -> If successful, grant access (create session/JWT).For this example, the state (
isVerified
) is temporary and managed in the React component. A real app needs persistence.7. Adding Security Features
Security is paramount for authentication flows.
!recipient
,!session_uuid
,!otp
). Enhance phone number validation using a robust library on the server (e.g., Google'slibphonenumber
via a Node.js port) to ensure format correctness before calling Plivo. Validatesession_uuid
format (it's typically a UUID). Ensure OTP is numeric and matches expected length (as implemented in 2.2)./api/otp/send
and/api/otp/verify
endpoints./api/otp/send
to X requests per phone number per hour./api/otp/verify
to Y attempts persession_uuid
.rate-limiter-flexible
orexpress-rate-limit
(if using Express middleware with Next.js, or adapt the logic). Vercel and Netlify also offer built-in or add-on solutions for edge rate limiting.rate-limiter-flexible
(conceptual):