서류 없이 5분 만에 끝내는 Flutter + Riverpod SMS 본인인증 구현하기
2026-06-01T01:02:17.258Z
![]()
서류 없이 5분 만에 끝내는 Flutter + Riverpod SMS 본인인증 구현하기
Flutter로 토이 프로젝트나 MVP를 개발 중이신가요? 서비스 런칭을 위해 회원가입을 만들다 보면 반드시 마주치는 장벽이 있습니다. 바로 **SMS 본인인증(OTP)**입니다.
기존의 문자 발송 API(포트원, 쿨에스엠에스 등)를 사용해 보셨다면 아실 겁니다.
- 사업자등록증 제출
- 발신번호 사전등록을 위한 통신사 가입증명원
- 며칠이 걸리는 심사 기간
개인 개발자나 사업자가 없는 초기 스타트업에게는 시작조차 할 수 없는 조건이죠. 이 글에서는 **서류 없이 가입 후 5분 만에 연동 가능한 초간단 API, EasyAuth(이지어스)**를 활용해 Flutter와 Riverpod로 완벽한 인증 플로우를 만드는 방법을 소개합니다.
왜 EasyAuth인가요?
EasyAuth는 개발자를 위한 가장 실용적인 SMS API입니다.
- 서류 불필요: 사업자등록증 없이 이메일 가입만으로 즉시 시작
- 자동 발신번호: 복잡한 발신번호 등록 없이 기본 번호 제공
- 합리적 가격: 건당 15~25원으로 기존(30~50원) 대비 절반 가격
- 단순한 구조:
/send와/verify단 두 개의 엔드포인트
1. Riverpod 인증 상태 정의하기
인증 과정은 크게 '입력 전', '발송 완료(타이머 동작)', '인증 성공', '에러' 상태로 나뉩니다. Riverpod의 Notifier를 활용해 상태 관리를 해보겠습니다.
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
enum AuthStatus { initial, sending, codeSent, verifying, success, error }
class AuthState {
final AuthStatus status;
final String? errorMessage;
AuthState({required this.status, this.errorMessage});
}
class AuthNotifier extends Notifier {
@override
AuthState build() => AuthState(status: AuthStatus.initial);
// 1. 인증번호 발송 (POST /send)
Future sendSms(String phone) async {
state = AuthState(status: AuthStatus.sending);
try {
final response = await http.post(
Uri.parse('https://api.easyauth.kr/send'),
headers: {'Authorization': 'Bearer YOUR_API_KEY'},
body: jsonEncode({'phone': phone}),
);
if (response.statusCode == 200) {
state = AuthState(status: AuthStatus.codeSent);
} else {
state = AuthState(status: AuthStatus.error, errorMessage: '발송 실패');
}
} catch (e) {
state = AuthState(status: AuthStatus.error, errorMessage: '네트워크 오류');
}
}
// 2. 인증번호 검증 (POST /verify)
Future verifyCode(String phone, String code) async {
state = AuthState(status: AuthStatus.verifying);
try {
final response = await http.post(
Uri.parse('https://api.easyauth.kr/verify'),
headers: {'Authorization': 'Bearer YOUR_API_KEY'},
body: jsonEncode({'phone': phone, 'code': code}),
);
if (response.statusCode == 200) {
state = AuthState(status: AuthStatus.success);
} else {
state = AuthState(status: AuthStatus.error, errorMessage: '인증번호 불일치');
}
} catch (e) {
state = AuthState(status: AuthStatus.error, errorMessage: '네트워크 오류');
}
}
}
final authProvider = NotifierProvider(() => AuthNotifier());
2. 완벽한 UI/UX 구현하기
상태에 따라 전화번호 입력창과 인증번호 입력창이 전환되는 UI를 구성합니다.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class SmsAuthScreen extends ConsumerWidget {
final phoneController = TextEditingController();
final codeController = TextEditingController();
@override
Widget build(BuildContext context, WidgetRef ref) {
final authState = ref.watch(authProvider);
final authNotifier = ref.read(authProvider.notifier);
return Scaffold(
appBar: AppBar(title: Text('SMS 본인인증')),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
controller: phoneController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(labelText: '휴대폰 번호 (- 없이 입력)'),
enabled: authState.status == AuthStatus.initial || authState.status == AuthStatus.error,
),
SizedBox(height: 16),
if (authState.status == AuthStatus.initial || authState.status == AuthStatus.error)
ElevatedButton(
onPressed: () => authNotifier.sendSms(phoneController.text),
child: Text('인증번호 받기'),
),
if (authState.status == AuthStatus.codeSent || authState.status == AuthStatus.verifying) ...[
TextField(
controller: codeController,
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: '인증번호 6자리'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () => authNotifier.verifyCode(phoneController.text, codeController.text),
child: authState.status == AuthStatus.verifying
? CircularProgressIndicator()
: Text('인증하기'),
),
],
if (authState.status == AuthStatus.success)
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text('✅ 인증이 완료되었습니다!', style: TextStyle(color: Colors.green, fontSize: 18)),
),
if (authState.errorMessage != null)
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text(authState.errorMessage!, style: TextStyle(color: Colors.red)),
),
],
),
),
);
}
}
3. 실무 적용 꿀팁 (Best Practices)
- Autofill 자동 완성:
TextField의autofillHints속성에[AutofillHints.oneTimeCode]를 추가하면 iOS/Android에서 문자로 온 인증번호를 키보드 상단에 자동으로 띄워줍니다. - 타이머 추가: SMS 발송 후 3분(180초) 타이머를 추가하여 보안을 강화하세요.
Timer.periodic을 사용해 상태에 남은 시간을 업데이트하면 됩니다. - 버튼 비활성화 중복 클릭 방지: API 통신 중(
sending,verifying상태)일 때는 버튼을 비활성화하여 중복 요청을 막아주세요.
마무리
지금까지 Flutter와 Riverpod, 그리고 EasyAuth를 활용하여 빠르고 깔끔한 SMS 인증 플로우를 구현해 보았습니다.
사이드 프로젝트나 스타트업 MVP 개발 시 문자 인증 때문에 막막하셨다면, 더 이상 통신사 서류와 씨름하지 마세요. 가입 즉시 10건의 무료 테스트 크레딧을 제공하는 EasyAuth로 지금 바로 인증 기능을 완성해 보세요!
비트베이크에서 광고를 시작해보세요
광고 문의하기다른 글 보기
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