비트베이크

[Next.js App Router] 서류 없이 5분 만에 SMS 휴대폰 본인인증 구현하기

2026-05-05T01:02:52.538Z

![Please provide the blog post topic to generate a relevant Unsplash search query.](Cannot provide a direct image URL as the blog post topic is missing, and I cannot browse Unsplash to select a specific image. Please provide the topic to generate a suitable search query.)

사이드 프로젝트에 SMS 인증, 왜 이렇게 힘들까?

사이드 프로젝트나 스타트업 MVP를 개발하다 보면 반드시 마주치는 장벽이 있습니다. 바로 **휴대폰 본인인증(SMS 인증)**입니다. 기능 자체는 단순해 보이지만, 막상 기존 벤더사(API)를 찾아보면 사업자등록증, 통신사 발신번호 사전등록, 이용증명원 등 요구하는 서류가 산더미입니다.

"단순히 테스트만 해보고 싶은데 서류부터 내라고?"

이런 고민을 해결하기 위해, 오늘은 서류 제출 없이 단 5분 만에 Next.js 14/15 App Router 환경에서 SMS OTP 인증을 구현하는 방법을 알아보겠습니다. 이를 위해 개발자를 위한 초간단 SMS 인증 API인 [EasyAuth(이지어스)]를 활용합니다.

이 글에서 다룰 내용

  1. Next.js App Router의 Route Handler를 활용한 서버리스 API 구성
  2. React Client Component를 이용한 OTP 인증 UI 구현
  3. 보안과 UX를 고려한 실무 팁 (정규화, 상태 관리)

1단계: API 라우트 설정 (Backend)

Next.js App Router에서는 app/api/.../route.ts 형태로 백엔드 API를 쉽게 만들 수 있습니다. 클라이언트 브라우저에서 직접 외부 API를 호출하면 API 키가 유출될 위험이 있으므로, Next.js 서버를 프록시로 사용합니다. EasyAuth는 단 두 개의 엔드포인트(/send, /verify)만 제공하므로 매우 직관적입니다.

1. 인증번호 발송 API (app/api/auth/send/route.ts)

import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  try {
    const { phone } = await request.json();

    // EasyAuth 발송 API 호출
    const response = await fetch('https://api.easyauth.co.kr/send', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.EASYAUTH_API_KEY}`,
      },
      body: JSON.stringify({ phone }),
    });

    const data = await response.json();
    return NextResponse.json(data, { status: response.status });
  } catch (error) {
    return NextResponse.json({ message: '발송 실패' }, { status: 500 });
  }
}

2. 인증번호 검증 API (app/api/auth/verify/route.ts)

import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  try {
    const { phone, code } = await request.json();

    // EasyAuth 검증 API 호출
    const response = await fetch('https://api.easyauth.co.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();
    return NextResponse.json(data, { status: response.status });
  } catch (error) {
    return NextResponse.json({ message: '검증 실패' }, { status: 500 });
  }
}

2단계: 클라이언트 UI 구현 (Frontend)

이제 사용자가 전화번호를 입력하고 문자로 받은 인증번호 6자리를 입력할 수 있는 UI를 만들어 봅니다.

전체 동작하는 코드 (app/components/SmsVerification.tsx)

'use client';

import { useState } from 'react';

export default function SmsVerification() {
  const [phone, setPhone] = useState('');
  const [code, setCode] = useState('');
  const [step, setStep] = useState(1); // 1: 번호 입력 단계, 2: 인증번호 입력 단계
  const [loading, setLoading] = useState(false);
  const [message, setMessage] = useState('');

  const handleSend = async () => {
    setLoading(true);
    setMessage('');
    try {
      const res = await fetch('/api/auth/send', {
        method: 'POST',
        body: JSON.stringify({ phone: phone.replace(/[^0-9]/g, '') }), // 숫자만 추출
      });

      if (res.ok) {
        setStep(2);
        setMessage('인증번호가 발송되었습니다. 문자를 확인해주세요.');
      } else {
        setMessage('발송에 실패했습니다. 번호를 다시 확인해주세요.');
      }
    } finally {
      setLoading(false);
    }
  };

  const handleVerify = async () => {
    setLoading(true);
    setMessage('');
    try {
      const res = await fetch('/api/auth/verify', {
        method: 'POST',
        body: JSON.stringify({ phone: phone.replace(/[^0-9]/g, ''), code }),
      });

      if (res.ok) {
        setMessage('✅ 인증이 완료되었습니다!');
        // TODO: 성공 후 회원가입 프로세스 진행 또는 토큰 발급 로직 연동
      } else {
        setMessage('❌ 인증번호가 일치하지 않습니다.');
      }
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <h2>휴대폰 본인인증</h2>

      {step === 1 &amp;&amp; (
        <div>
           setPhone(e.target.value)}
            className="p-3 border rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none"
            maxLength={13}
          /&gt;
          
            {loading ? '발송 중...' : '인증번호 받기'}
          
        </div>
      )}

      {step === 2 &amp;&amp; (
        <div>
           setCode(e.target.value)}
            className="p-3 border rounded-md focus:ring-2 focus:ring-blue-500 focus:outline-none tracking-widest text-center text-lg"
            maxLength={6}
          /&gt;
          
            {loading ? '확인 중...' : '인증 완료'}
          
           setStep(1)}
            className="text-sm text-gray-500 underline mt-2 text-center"
          &gt;
            번호 다시 입력하기
          
        </div>
      )}

      {message &amp;&amp; (
        <p>
          {message}
        </p>
      )}
    </div>
  );
}

실무 팁과 보안 베스트 프랙티스 (Tips & Best Practices)

안전하고 사용자 친화적인 SMS 인증을 위해 아래 항목들을 챙겨보세요.

  1. 전화번호 정규화 (Formatting): 사용자는 010-1234-5678, 010 1234 5678 등 예측 불가능한 형태로 번호를 입력합니다. 위 코드의 .replace(/[^0-9]/g, '')처럼 클라이언트와 서버 양측에서 숫자만 추출하도록 처리하는 것이 가장 안전합니다.
  2. 환경 변수 보호 (Security): EASYAUTH_API_KEY는 반드시 .env.local에 보관해야 합니다. NEXT_PUBLIC_ 접두사를 붙여 클라이언트에 키를 노출하는 실수를 절대 범하지 마세요. Route Handler가 프록시 역할을 하는 이유가 바로 이 때문입니다.
  3. 버튼 연타 방지 (Rate Limiting): loading 상태를 적극 활용하여, API 응답이 오기 전까지 버튼을 비활성화(disabled)해야 합니다. 의도치 않은 중복 API 호출로 인한 문자 발송 비용 낭비를 막을 수 있습니다.

결론: 복잡한 서류 없는 EasyAuth로 5분 만에 시작하세요

지금까지 Next.js App Router 환경에서 간단하게 SMS 휴대폰 본인인증을 구현하는 방법을 완성 코드로 알아보았습니다. 로직 자체는 간단하지만, 그동안 서비스 연동의 가장 큰 허들은 '복잡한 행정 서류'였습니다.

하지만 이커머스, 서비스 플랫폼, 혹은 빠르게 MVP를 검증해야 하는 스타트업이라면 개발에만 집중해야 합니다. 이지어스(EasyAuth)는 개발자의 이런 고충을 해결하기 위해 탄생했습니다.

  • 서류 제로: 사업자등록증, 통신사 가입 증명원 제출 없음
  • 빠른 시작: 가입 즉시 API 연동이 가능하며, 복잡한 대표번호 사전등록 없이 자동 발신번호가 세팅됩니다.
  • 가벼운 가격: 기존 건당 30~50원 수준이던 문자 발송 비용을 15~25원으로 확 낮췄습니다.
  • 심플한 API: 복잡한 SDK 없이 POST /send, POST /verify 두 번의 호출로 끝납니다.

현재 가입 시 10건의 무료 테스트 크레딧을 바로 제공하고 있습니다. 지금 진행 중인 토이 프로젝트나 사이드 프로젝트에 SMS 인증이 필요하다면, 5분 만에 서류 없이 이지어스로 연동을 마쳐보세요!

비트베이크에서 광고를 시작해보세요

광고 문의하기

다른 글 보기

2026-06-04T01:04:15.823Z

The 2026 E-Commerce New Product Launch Survival Formula: Dominating Platform Search Rankings in 7 Days via Reward-Based Trials and Purchase Verification

2026-06-04T01:04:15.800Z

2026 이커머스 신제품 론칭 생존 공식: 리워드형 체험단과 구매 인증으로 7일 만에 플랫폼 검색 랭킹 장악하기

2026-06-01T01:01:58.264Z

Surviving the 2026 Cookieless Era for B2C: Building Zero-Party Data with Reward-Based Quiz Marketing

2026-06-01T01:01:58.231Z

2026 쿠키리스 시대의 B2C 생존법: 리워드 기반 퀴즈 마케팅으로 제로파티 데이터 구축하기

서비스

피드자주 묻는 질문고객센터

문의

비트베이크

레임스튜디오 | 사업자 등록번호 : 542-40-01042

경기도 남양주시 와부읍 수례로 116번길 16, 4층 402-제이270호

트위터인스타그램네이버 블로그