2025.6.26 목요일의 공부기록
이번 글에서는 Next.js 애플리케이션에서 Twilio와 crypto
모듈을 활용하여 SMS 인증 기능을 구현한 내용을 다룬다.
Twilio는 SMS, 음성, 영상, 이메일 등 다양한 통신 서비스를 제공하는 클라우드 기반 플랫폼이다. 특히 SMS 서비스를 통해 개발자가 간편하게 문자 메시지를 전송하고 수신할 수 있도록 API를 제공한다.
SMS 인증에서 사용하는 토큰(인증 번호)은 중복되지 않고 예측 불가능한 랜덤 숫자로 만들어져야 한다. 이를 위해 Node.js의 내장 모듈인 crypto
의 randomInt(min, max)
메서드를 사용했다.
import crypto from "crypto";
async function getToken() {
const token = crypto.randomInt(100000, 999999).toString(); // 6자리 랜덤 숫자 생성
// 생성된 토큰이 이미 존재하는지 확인하여 중복 방지
const existingToken = await db.sMSToken.findUnique({
where: {
token,
},
select: {
id: true,
},
});
if (existingToken) {
// 중복된 토큰이라면 재귀적으로 새 토큰 생성
return getToken();
}
return token;
}
crypto.randomInt(min, max)
는 min
과 max
사이의 랜덤 정수를 반환한다.actions.ts
사용자가 인증을 요청하면 다음과 같은 프로세스가 진행된다:
구체적인 구현 코드:
...
export async function smsLogIn(prevState: ActionState, formData: FormData) {
const phone = formData.get("phone");
const token = formData.get("token");
if (!prevState.token) {
const result = phoneSchema.safeParse(phone);
if (!result.success) {
return { token: false, error: result.error.flatten() };
} else {
// delete previous token
await db.sMSToken.deleteMany({
where: {
user: {
phone: result.data,
},
},
});
// create new token
const token = await getToken();
await db.sMSToken.create({
data: {
token,
user: {
connectOrCreate: {
where: {
phone: result.data,
},
create: {
phone: result.data,
username: crypto.randomBytes(10).toString("hex"),
},
},
},
},
});
// send token to phone using twilio
return { token: true };
}
} else {
const result = tokenSchema.safeParse(token);
if (!result.success) {
return {
token: true,
error: result.error.flatten(),
};
} else {
redirect("/");
}
}
}
connectOrCreate
를 통해 사용자 정보가 없다면 자동으로 사용자 데이터를 생성한다. (username
은 랜덤으로 생성됨)단계 | 설명 | 비고 |
---|---|---|
1 | 클라이언트가 전화번호 입력 후 SMS 인증 요청 | 전화번호 형식 검증 |
2 | 기존 발급된 토큰 삭제 | 중복 인증 방지 |
3 | 새로운 토큰 생성 및 저장 | 중복 검사 수행 |
4 | Twilio로 토큰 전송 | 사용자에게 SMS 발송 |
5 | 사용자로부터 입력받은 토큰 검증 | 별도 검증 로직 필요 |
crypto.randomInt
를 활용해 안전한 SMS 인증을 구현할 수 있다.이 글을 기반으로 Next.js 프로젝트에 강력한 SMS 인증 기능을 손쉽게 추가할 수 있을 것이다.