Implementing SMS Authentication in Next.js App Router in 5 Minutes (Zero Paperwork)
Have you ever given up on adding SMS auth to your side project?
When building a toy project or a startup MVP, implementing SMS Phone Authentication is essential to prevent malicious bots and verify real users. However, finding a developer-friendly API often leads to hitting a massive wall of bureaucracy.
- "Please submit your business registration certificate."
- "We need carrier usage certificates."
- "Pre-register your sender caller ID."
For solo developers, freelancers, or MVP startup teams who need to test their hypotheses fast, these complex paperwork requirements are a total nightmare.
In this tutorial, we will learn how to implement SMS OTP authentication in Next.js App Router in just 5 minutes, completely paperwork-free.
💡 Why Next.js App Router?
Next.js App Router makes it incredibly easy to separate server-side logic (Route Handlers) from Client Components. This allows you to safely hide your SMS API keys on the server while providing a seamless, interactive UI for your users.
🛠️ Step-by-Step Implementation Guide
The SMS authentication logic requires only two endpoints:
- Send: When the user enters their phone number.
- Verify: When the user enters the OTP code.
Let's build two API routes and one client component.
1. Send OTP API Route (Server)
First, create the app/api/auth/send/route.ts file.
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
try {
const { phone } = await request.json();
// Calling EasyAuth, the zero-paperwork SMS API
const response = await fetch('https://api.easyauth.kr/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.EASYAUTH_API_KEY}`
},
body: JSON.stringify({ phone })
});
if (!response.ok) throw new Error('Failed to send');
return NextResponse.json({ success: true, message: 'OTP sent successfully.' });
} catch (error) {
return NextResponse.json({ success: false, error: 'Internal Server Error' }, { status: 500 });
}
}
2. Verify OTP API Route (Server)
Next, create app/api/auth/verify/route.ts.
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
try {
const { phone, code } = await request.json();
const response = await fetch('https://api.easyauth.kr/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.EASYAUTH_API_KEY}`
},
body: JSON.stringify({ phone, code })
});
const data = await response.json();
if (!data.success) {
return NextResponse.json({ success: false, message: 'Invalid OTP code.' }, { status: 400 });
}
return NextResponse.json({ success: true, message: 'Verification complete.' });
} catch (error) {
return NextResponse.json({ success: false, error: 'Internal Server Error' }, { status: 500 });
}
}
3. SMS Auth UI Component (Client)
Now, let's create the frontend interface (app/page.tsx or a custom component).
'use client';
import { useState } from 'react';
export default function SmsAuth() {
const [phone, setPhone] = useState('');
const [code, setCode] = useState('');
const [step, setStep] = useState<'INPUT_PHONE' | 'INPUT_CODE'>('INPUT_PHONE');
const handleSend = async () => {
const res = await fetch('/api/auth/send', {
method: 'POST',
body: JSON.stringify({ phone }),
});
if (res.ok) setStep('INPUT_CODE');
};
const handleVerify = async () => {
const res = await fetch('/api/auth/verify', {
method: 'POST',
body: JSON.stringify({ phone, code }),
});
const data = await res.json();
if (data.success) {
alert('Verification Successful! 🎉');
} else {
alert('Please check your OTP code and try again.');
}
};
return (
<div>
<h2>Phone Verification</h2>
<div>
setPhone(e.target.value)}
className="border p-2 rounded"
disabled={step === 'INPUT_CODE'}
/>
{step === 'INPUT_PHONE' ? (
Get OTP
) : (
<>
setCode(e.target.value)}
className="border p-2 rounded"
/>
Verify
</>
)}
</div>
</div>
);
}
💡 Tips & Best Practices
- Phone Number Formatting: Users might type hyphens (
-). It's best to strip them using.replace(/[^0-9]/g, '')before sending the payload to the server. - Rate Limiting: To prevent SMS bombing and abuse, implement rate limiting on your API routes using tools like Redis (e.g., Upstash) based on IP or phone numbers.
🚀 EasyAuth: The Zero-Paperwork Developer SMS API
The api.easyauth.kr endpoint used in the code above belongs to EasyAuth(이지어스), a hyper-simple SMS authentication API built specifically for developers.
Unlike traditional SMS providers that require business certificates and a pre-registered caller ID, EasyAuth lets you integrate and send SMS within 5 minutes of signing up.
Why choose EasyAuth?
- 🚫 Zero Paperwork: Automatically handles caller ID; no pre-registration required.
- ⚡ Instant Setup: Perfect for solo developers and freelancers—start sending immediately.
- 💰 Affordable Pricing: Costs only 15~25 KRW per message (compared to the standard 30~50 KRW).
- 🎁 Free Trial: Get 10 free credits immediately upon signup to test your integration.
If you are building an MVP, a toy project, or an e-commerce platform and need SMS verification, don't waste your time with bureaucratic paperwork. Try EasyAuth today and implement your auth logic in just 5 minutes!