비트베이크

[AWS Cognito] 골치 아픈 SMS 발송 실패 해결: 5분 만에 국내 커스텀 SMS 람다(Lambda) 연동하기

2026-05-22T01:03:05.469Z

Search query for professional, modern, tech-related images suitable for developer/authentication content, with a clean aesthetic and space for text overlay: 'Cyber security abstract'

AWS Cognito SMS 인증, 혹시 이런 문제 겪고 계신가요?

빠른 MVP 개발이나 사이드 프로젝트를 위해 AWS Cognito로 사용자 인증을 구현해보신 개발자라면, 글로벌 서비스의 편리함 이면에 숨겨진 커다란 장벽에 부딪혀 보셨을 겁니다. 바로 한국 번호(+82) SMS 인증 발송 실패 문제입니다.

기본적으로 Cognito는 AWS SNS(Simple Notification Service)를 통해 SMS를 발송합니다. 하지만 한국의 통신 환경과 강력한 스팸 규제로 인해 AWS SNS로 발송된 인증 문자는 누락되거나 지연되는 경우가 허다합니다. 게다가 건당 비용도 매우 비싸 초기 스타트업이나 1인 개발자에게는 큰 부담이 됩니다.

그렇다면 국내 SMS API로 눈을 돌리면 어떨까요?

이 문제를 해결하기 위해 국내 유명 SMS 벤더사(A사, C사 등)의 API 문서를 열어보면 또 다른 절망이 시작됩니다.

  • "사업자등록증명원 사본을 제출해주세요."
  • "통신서비스 이용증명원을 발급받아 첨부해주세요."
  • "발신번호 사전 등록에는 최대 3~5영업일이 소요됩니다."

서버 코딩은 1시간이면 끝나는데, 서류 심사 때문에 일주일을 허비해야 합니다. 법인이 없는 사이드 프로젝트 팀이나 프리랜서 개발자에게는 사실상 '도입 불가' 판정이나 다름없습니다.


서류 없이 5분 만에 시작하는 이지어스(EasyAuth)

이러한 개발자들의 고충을 완벽하게 해결해 주는 서비스가 바로 **EasyAuth(이지어스)**입니다. 이지어스는 오직 '개발자의 생산성'에 집중한 초간단 SMS 인증 API입니다.

  • 서류 완전 불필요: 사업자등록증, 이용증명원 등 어떠한 서류 제출도 없습니다.
  • 즉시 시작: 회원가입 후 발급받은 API Key로 5분 안에 연동을 끝낼 수 있습니다.
  • 자동 발신번호: 귀찮은 대표번호 사전등록 없이 이지어스의 발신번호 시스템이 자동으로 적용됩니다.
  • 합리적 가격: 기존 30~50원씩 하던 문자를 건당 15~25원의 저렴한 비용으로 제공합니다.
  • 무료 체험: 가입 즉시 테스트용 10건이 무료로 충전됩니다.

특히 이지어스는 POST /send(발송)와 POST /verify(검증) 단 두 개의 엔드포인트로 인증의 전 과정을 처리합니다. 데이터베이스에 OTP 번호를 저장하고 만료 시간을 관리할 필요조차 없습니다.

이 글에서는 AWS Cognito의 Custom Authentication Challenge (사용자 지정 인증 챌린지) Lambda 트리거를 활용하여, 기존의 불안정한 SNS를 걷어내고 이지어스 API를 연동하는 방법을 단계별로 알아보겠습니다.


아키텍처 결정: Custom SMS Sender vs Custom Auth Challenge

Cognito에 커스텀 SMS를 붙이는 방법은 크게 두 가지가 있습니다.

  1. Custom SMS Sender 트리거: Cognito가 OTP를 생성한 뒤 AWS KMS로 암호화하여 Lambda로 보냅니다. 개발자는 KMS 복호화 코드를 작성하고 SMS 발송 API만 호출합니다.
  2. Custom Auth Challenge 트리거: OTP 생성부터 검증까지의 모든 흐름(State)을 개발자가 제어합니다.

우리는 Custom Auth Challenge 방식을 사용할 것입니다. 왜냐하면 이지어스는 자체적으로 /send/verify 엔드포인트를 통해 OTP 상태를 완벽하게 관리해주기 때문입니다. 이 방식을 사용하면 번거로운 AWS KMS 세팅과 복호화 로직 없이, 이지어스의 강력한 기능을 100% 활용할 수 있습니다.


Step-by-Step 구현 가이드

Cognito의 Custom Auth Flow는 세 가지 Lambda 함수가 유기적으로 동작하며 완성됩니다. Node.js 기반으로 빠르게 작성해 보겠습니다.

1. Define Auth Challenge Lambda (흐름 제어)

이 함수는 인증의 전체적인 상태(State Machine)를 관리합니다. 사용자가 인증을 완료했는지, 실패했는지 판단합니다.

// defineAuthChallenge.js
exports.handler = async (event) => {
    if (event.request.session && event.request.session.length === 0) {
        // 첫 번째 시도: 커스텀 챌린지를 시작합니다.
        event.response.issueTokens = false;
        event.response.failAuthentication = false;
        event.response.challengeName = 'CUSTOM_CHALLENGE';
    } else if (
        event.request.session &&
        event.request.session.length > 0 &&
        event.request.session.slice(-1)[0].challengeResult === true
    ) {
        // 사용자가 올바른 OTP를 입력했을 경우: 토큰 발급
        event.response.issueTokens = true;
        event.response.failAuthentication = false;
    } else {
        // 최대 시도 횟수 초과 또는 실패
        event.response.issueTokens = false;
        event.response.failAuthentication = true;
    }
    return event;
};

2. Create Auth Challenge Lambda (이지어스로 SMS 발송)

사용자가 전화번호를 입력하고 로그인/가입을 시도할 때 호출됩니다. 여기서 이지어스의 POST /send API를 호출합니다.

// createAuthChallenge.js
exports.handler = async (event) => {
    if (event.request.challengeName === 'CUSTOM_CHALLENGE') {
        const phoneNumber = event.request.userAttributes.phone_number;
        
        // 세션에 이미 챌린지가 있다면 발송을 건너뛰고, 첫 시도에만 발송합니다.
        if (event.request.session && event.request.session.length === 0) {
            try {
                // 이지어스 API 호출: 인증번호 발송
                const response = await fetch('https://api.easyauth.co/v1/send', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${process.env.EASYAUTH_API_KEY}`
                    },
                    body: JSON.stringify({ phone: phoneNumber })
                });
                
                if (!response.ok) {
                    throw new Error('EasyAuth 발송 실패');
                }
            } catch (error) {
                console.error("SMS Send Error:", error);
                throw new Error("SMS 발송 중 오류가 발생했습니다.");
            }
        }

        // 프론트엔드로 전달할 퍼블릭 파라미터 (UI 표시용)
        event.response.publicChallengeParameters = { phone: phoneNumber };
        // Verify 함수로 전달할 프라이빗 파라미터
        event.response.privateChallengeParameters = { challenge: 'EASYAUTH_OTP' };
    }
    
    return event;
};

3. Verify Auth Challenge Lambda (이지어스로 OTP 검증)

사용자가 프론트엔드(Next.js, React 등)에서 6자리 코드를 입력하여 제출하면 호출됩니다. 이지어스의 POST /verify API로 검증을 요청합니다.

// verifyAuthChallenge.js
exports.handler = async (event) => {
    if (event.request.privateChallengeParameters.challenge === 'EASYAUTH_OTP') {
        const answer = event.request.challengeAnswer; // 사용자가 입력한 코드
        const phoneNumber = event.request.userAttributes.phone_number;

        try {
            // 이지어스 API 호출: 인증번호 검증
            const response = await fetch('https://api.easyauth.co/v1/verify', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${process.env.EASYAUTH_API_KEY}`
                },
                body: JSON.stringify({
                    phone: phoneNumber,
                    code: answer
                })
            });

            const data = await response.json();
            
            // 이지어스 서버의 검증 결과(boolean)를 Cognito에 전달
            event.response.answerCorrect = data.success === true;
            
        } catch (error) {
            console.error("SMS Verify Error:", error);
            event.response.answerCorrect = false;
        }
    }
    
    return event;
};

프론트엔드 연동 예시 (Next.js / AWS Amplify)

람다 트리거 설정이 끝났다면, 프론트엔드에서는 Amplify 라이브러리를 통해 매우 직관적으로 이 흐름을 제어할 수 있습니다.

import { Auth } from 'aws-amplify';

// 1. 전화번호로 로그인 (또는 회원가입) 시도 -> Create Auth Challenge 트리거 작동
let cognitoUser;
async function signIn(phoneNumber) {
    try {
        cognitoUser = await Auth.signIn(phoneNumber);
        console.log("SMS가 발송되었습니다. 코드를 입력해주세요.");
    } catch (error) {
        console.error("로그인 에러", error);
    }
}

// 2. 사용자가 입력한 OTP 제출 -> Verify Auth Challenge 트리거 작동
async function verifyCode(otpCode) {
    try {
        await Auth.sendCustomChallengeAnswer(cognitoUser, otpCode);
        console.log("인증 성공! 로그인 되었습니다.");
    } catch (error) {
        console.error("인증 실패 (코드가 틀렸거나 만료됨)", error);
    }
}

실무 팁 및 보안 고려사항 (Best Practices)

  1. Lambda 타임아웃 연장: 기본 Lambda 생성 시 타임아웃이 3초로 설정되어 있습니다. 외부 API(이지어스) 통신이 포함되므로 넉넉하게 10초로 늘려주는 것을 권장합니다.
  2. API Key 보안: EASYAUTH_API_KEY는 코드에 하드코딩하지 말고, AWS Systems Manager Parameter Store나 Lambda 환경 변수(암호화 적용)를 사용해 안전하게 보관하세요.
  3. CloudWatch 로깅 주의: Lambda에서 console.log(event)를 실행하면 사용자의 전화번호(PII)가 로그에 남게 됩니다. 운영 환경에서는 민감한 데이터를 마스킹 처리하여 로깅해야 합니다.

결론

AWS Cognito와 기본 SNS의 조합은 글로벌 스탠다드일지 모르나, 국내 서비스 환경에서는 비용과 안정성 측면에서 분명한 한계를 가집니다. 그렇다고 복잡한 서류 심사와 레거시 API 규격을 요구하는 기존 벤더사를 선택하자니 초기 개발 속도가 생명인 스타트업과 개발자에게는 너무 가혹합니다.

이제 **EasyAuth(이지어스)**와 Cognito Custom Lambda Trigger의 조합으로 이 딜레마를 탈출하세요. 서류 심사 대기 없이 단 5분 만에, 기존 대비 반값(15~25원)으로 안정적인 국내 SMS 인증 시스템을 구축할 수 있습니다.

지금 바로 [이지어스 홈페이지]에 가입하고 무료로 제공되는 10건의 크레딧으로 이 튜토리얼을 직접 테스트해 보세요! 여러분의 소중한 개발 시간을 비즈니스 로직 구현에만 온전히 집중하실 수 있습니다.

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

광고 문의하기

다른 글 보기

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호

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