Frequently Asked Questions
Implement 2FA by integrating NextAuth.js for authentication, Plivo for SMS delivery, and Prisma for database management. This setup enables a secure login flow where users verify their identity with an OTP sent via SMS after entering their credentials, enhancing account security.
Plivo is the communications platform API used to send SMS messages containing the One-Time Passwords (OTPs) for two-factor authentication. It's a key component for delivering the verification codes to users' phones.
NextAuth.js uses JSON Web Tokens (JWT) to manage session state and store authentication information, including whether 2FA has been verified in the current session. This approach enhances security by encoding user data and verification status within the token itself.
Use SMS-based OTP authentication to enhance security when users log in with credentials. After initial login, if 2FA is enabled, an OTP is required before granting full access to protected resources like a dashboard.
Yes, Prisma supports multiple database providers including PostgreSQL, MySQL, and SQLite. While the example uses PostgreSQL, you can adapt the schema and database URL in schema.prisma and .env to your preferred database.
Configure the Plivo Node.js client by setting environment variables (PLIVO_AUTH_ID, PLIVO_AUTH_TOKEN, PLIVO_PHONE_NUMBER) with your Plivo credentials. The sendSms utility function in plivo.ts then handles sending SMS messages using these credentials.
Hashing the OTP with bcrypt before storing it in the database significantly enhances security by preventing the storage of sensitive information in plain text. Only the hash is stored, and the submitted OTP is compared against the hash for verification.
The verifyOtp utility function handles OTP expiry by comparing the current time to the stored twoFactorExpiry timestamp. If expired, it clears the OTP data and returns false, prompting the user to request a new code.
The provided code uses next-auth@beta, specifically for compatibility with the Next.js App Router and Server Actions. The beta version supports the latest features and conventions of the App Router.
The middleware.ts file configures route protection by checking the twoFactorVerified status within the session. If 2FA is enabled but not verified, the middleware redirects to the /verify-otp page.
The twoFactorVerified flag in both the session and JWT indicates whether a user has successfully completed 2FA for the current session. This ensures protected routes are only accessible after both credential and OTP verification.
The generateOtp utility function uses the otp-generator library to create secure, numeric OTPs of a specified length (default is 6 digits). This function ensures the randomness and format of the codes.
Two configurations (auth.config.ts, auth.ts) are used to accommodate Next.js middleware. auth.config.ts contains minimal callbacks and settings needed for early checks before full initialization in auth.ts.
If Plivo credentials are missing during development, the sendSms function logs a warning and simulates sending the SMS instead of throwing an error. This allows development to proceed without actual SMS delivery.
How to Implement SMS Two-Factor Authentication with Plivo, NextAuth.js & Next.js
Introduction
<!-- DEPTH: Introduction lacks security context and real-world threat examples (Priority: Medium) --> <!-- GAP: Missing comparison with other 2FA methods (TOTP, hardware keys) to justify SMS choice (Type: Substantive) --> <!-- GAP: No discussion of SMS 2FA security limitations (SIM swapping, SS7 attacks) (Type: Critical) -->
Implement SMS-based two-factor authentication (2FA) in your Next.js application using Plivo's SMS API and NextAuth.js for session management. This tutorial demonstrates how to build a secure authentication system where users verify their identity through SMS one-time passwords (OTP) after entering their login credentials.
Two-factor authentication significantly strengthens application security by requiring both knowledge-based credentials (email and password) and possession-based verification (mobile device with SMS access). This guide covers Next.js 15 project setup, Plivo SMS integration, NextAuth.js authentication flow customization, OTP generation and verification, user 2FA preference management, and production deployment strategies.
What You'll Build:
Create a production-ready Next.js authentication system with:
Technologies & Requirements:
create-next-app).System Architecture:
Prerequisites:
<!-- GAP: Missing step-by-step instructions for obtaining Plivo credentials (Type: Substantive) -->
node --version.shadcn/uifor UI components, or adapt examples to your preferred library.Final Outcome:
A Next.js application where users can:
Verification Date: All technology versions and requirements verified as of January 2025.
How to Set Up Your Next.js Project with Plivo SMS Authentication
Initialize your Next.js 15 application and install the required dependencies for SMS-based two-factor authentication.
Step 1: Create Your Next.js Application
Open your terminal and create a new Next.js project with TypeScript and Tailwind CSS:
This command scaffolds a Next.js application using the App Router architecture, TypeScript for type safety, Tailwind CSS for styling, and ESLint for code quality.
Step 2: Install Required Dependencies for SMS 2FA
<!-- DEPTH: Package installation section could benefit from version compatibility matrix (Priority: Low) -->
Install NextAuth.js, Prisma ORM, Plivo SDK, and authentication utility libraries:
Package explanations:
next-auth@beta: Authentication library for Next.js. Install the beta version for Next.js 14+ and App Router compatibility. NextAuth.js v5 is rebranding as Auth.js (documentation at authjs.dev).@auth/prisma-adapter: Connects NextAuth with Prisma database.prisma: Database ORM for PostgreSQL, MySQL, or SQLite (Prisma 6.x supports PostgreSQL 9.6+).plivo-node: Official Plivo Node.js SDK for SMS messaging.bcrypt: Password and OTP hashing library for secure storage.zod: Runtime type validation and schema validation.otp-generator: Generate secure numeric one-time passwords.@types/*: TypeScript type definitions for development.Step 3: Initialize Prisma Database
<!-- GAP: Missing database setup instructions for cloud providers (Supabase, PlanetScale, Neon) (Type: Substantive) -->
Set up Prisma with PostgreSQL as your database provider:
This command creates:
prisma/schema.prisma: Database schema definition file..env: Environment configuration file withDATABASE_URL.Environment variable details:
<!-- EXPAND: Could add security best practices section for environment variables (Type: Enhancement) -->
DATABASE_URL: PostgreSQL connection string for your database. Update with your actual credentials and host information.NEXTAUTH_SECRET: Random secret string for encrypting JWT tokens and session cookies. Critical for authentication security. Generate usingopenssl rand -base64 32on Linux/macOS.NEXTAUTH_URL: Your application's canonical URL. Required for NextAuth callback URLs and redirects.PLIVO_AUTH_ID/PLIVO_AUTH_TOKEN: Plivo API credentials from your dashboard. Keep these secure and never commit to version control.PLIVO_PHONE_NUMBER: Your Plivo SMS-enabled phone number in E.164 format (e.g., +12345678900).OTP_EXPIRY_MINUTES: OTP validity duration in minutes (default: 5 minutes).Step 4: Configure Environment Variables for Plivo
Open the
.envfile and add your database connection string and Plivo API credentials. Obtain Plivo credentials from your Plivo Console (Dashboard → API Keys & Credentials).Step 5: Define Database Schema for 2FA Authentication
<!-- DEPTH: Schema design lacks explanation of security considerations for storing phone numbers (Priority: Medium) --> <!-- GAP: Missing discussion of GDPR/privacy compliance for phone number storage (Type: Critical) -->
Update
prisma/schema.prismato include NextAuth models and custom fields for SMS two-factor authentication.Database schema key components:
Account,Session,User, andVerificationTokenfor authentication state management.passwordfield toUsermodel for email/password login.Usermodel:phoneNumber: Stores user's verified phone number for SMS OTP delivery (unique constraint).twoFactorEnabled: Boolean flag indicating whether SMS 2FA is active for the user account.twoFactorSecret: Stores hashed OTP temporarily during verification (never store plain text OTPs).twoFactorExpiry: Timestamp for OTP expiration validation.twoFactorVerifiedfield toSessionmodel to track 2FA completion status per login session.Step 6: Run Database Migrations
Generate and apply your Prisma database schema:
This command performs three operations:
schema.prismadefinition.Step 7: Understand the Project Structure
Your Next.js application structure organizes authentication components as follows:
This architecture separates authentication concerns using Next.js App Router route groups:
(auth)for public authentication pages and(protected)for secured application routes.How to Configure NextAuth.js with Plivo SMS Integration
Configure NextAuth.js v5 (Auth.js) to handle credential authentication and integrate Plivo for SMS-based OTP delivery.
Configure Prisma Client Singleton
Create a singleton Prisma client instance to prevent connection pool exhaustion in development:
Set Up Plivo Client for SMS Delivery
<!-- DEPTH: Plivo client setup lacks error handling best practices and retry logic (Priority: High) --> <!-- GAP: Missing rate limiting considerations for SMS sending (Type: Substantive) --> <!-- EXPAND: Could add SMS template customization and internationalization (Type: Enhancement) -->
Configure the Plivo SMS client using your API credentials from environment variables:
Configure NextAuth.js Session and JWT Types
NextAuth.js v5 requires two configuration files:
auth.config.tsfor middleware andauth.tsfor the main authentication logic.First, extend the Session and JWT types using TypeScript module augmentation to add custom 2FA properties:
Create NextAuth Configuration for Middleware (auth.config.ts)
<!-- DEPTH: Middleware configuration lacks explanation of edge cases and redirect loops (Priority: Medium) -->
This configuration file handles route protection and session checks in Next.js middleware:
Create Main NextAuth Configuration (auth.ts)
<!-- DEPTH: Authentication flow lacks comprehensive error scenarios and user feedback mechanisms (Priority: High) --> <!-- GAP: Missing brute force protection and rate limiting for OTP attempts (Type: Critical) --> <!-- GAP: No discussion of backup codes or account recovery if phone is lost (Type: Critical) -->
Implement the Credentials provider with Plivo SMS integration for OTP delivery:
Key authentication flow elements:
PrismaAdapterto synchronize NextAuth session state with your PostgreSQL database.Credentialsprovider with Zod schema validation for email and password.twoFactorEnabledflag set.twoFactorVerified: falseto trigger middleware redirect to verification page.Configure Next.js Middleware for Route Protection
Create middleware to protect authenticated routes based on 2FA verification status:
Implement OTP Generation and Verification Utilities
<!-- DEPTH: OTP utilities lack discussion of cryptographic security considerations (Priority: High) --> <!-- GAP: Missing rate limiting for OTP verification attempts (Type: Critical) --> <!-- EXPAND: Could add audit logging for security events (Type: Enhancement) -->
Create utility functions for secure OTP generation and validation against stored hashes:
<!-- GAP: Document is incomplete - missing sections on UI implementation, testing, and deployment (Type: Critical) --> <!-- GAP: Missing troubleshooting section for common issues (Type: Substantive) --> <!-- GAP: No section on monitoring and observability for 2FA system (Type: Substantive) --> <!-- EXPAND: Could add section on migrating existing users to 2FA (Type: Enhancement) --> <!-- EXPAND: Could add performance optimization tips for high-volume SMS sending (Type: Enhancement) -->