
모바일 앱을 만들다 보면 늘 '로그인 기능'을 어떻게 구현할까 고민하게 된다. 사용자 데이터를 안전하게 관리하고 개인화된 경험을 주는 건 중요하니까. 처음엔 직접 다 만들어볼까 했는데, 그러기엔 너무 복잡하고 보안도 걱정됐다. 그러다 Firebase Authentication을 만나게 되었고, 이게 React Native 앱에 생각보다 잘 맞아서 요즘은 늘 이걸로 작업하고 있다.
이번 글은 내가 Firebase 인증을 사용하면서 겪었던 과정과 깨달음, 그리고 나름의 팁들을 일기처럼 기록해본 것이다. 혹시 나처럼 인증 기능 때문에 헤매는 개발자가 있다면, 이 글이 조금이나마 도움이 되면 좋겠다.
처음엔 그저 '구글에서 제공하는 인증 서비스'라고만 생각했다. 그런데 써보니까 훨씬 더 대단한 녀석이었다.
@react-native-firebase 패키지를 사용하면 React Native 앱에서도 마치 네이티브 앱처럼 Firebase 기능을 자연스럽게 쓸 수 있었다. 이게 가장 큰 매력이었다.Firebase Auth를 쓰려면 몇 가지 준비가 필요했다.
Firebase 프로젝트 만들기: Firebase 콘솔에 들어가서 새 프로젝트를 만들었다. 그리고 내가 만들 앱이 모바일 앱이니까, Android와 iOS 앱으로 등록해서 google-services.json (Android) 파일이랑 GoogleService-Info.plist (iOS) 파일을 다운받았다. 이 파일들을 내 React Native 프로젝트의 각 플랫폼 폴더에 잘 넣어주는 게 핵심이었다. 이걸 안 하면 아무리 코드를 잘 짜도 작동하지 않았다.
SDK 설치:
npm install @react-native-firebase/app @react-native-firebase/auth
설치 후에 따로 initializeApp 같은 걸 호출할 필요는 없었다. @react-native-firebase/app이 네이티브 단에서 알아서 Firebase를 초기화해줬기 때문에, 나는 그냥 auth() 객체를 가져다 쓰기만 하면 됐다. 처음엔 좀 헷갈렸는데, 알고 나니 엄청 편했다.
이제 실제로 사용자가 내 앱에 들어오고 나가는 핵심 기능을 구현할 차례였다. @react-native-firebase/auth 하나면 충분했다.
import auth from '@react-native-firebase/auth';
import { Alert } from 'react-native'; // 사용자에게 알림을 띄워주려고 import했다.
// 회원가입 함수: 이메일이랑 비밀번호 받아서 시도했다. 에러 처리는 필수였다.
const handleSignUp = async (email, password) => {
try {
const userCredential = await auth().createUserWithEmailAndPassword(email, password);
console.log('회원가입 성공:', userCredential.user.email);
Alert.alert('성공', '회원가입이 완료되었습니다! 이메일 인증을 해주세요.');
// 회원가입 성공하면 바로 이메일 인증 메일을 보내는 게 사용자 경험에 좋았다.
await userCredential.user.sendEmailVerification();
} catch (error) {
console.error('회원가입 실패:', error.code, error.message);
if (error.code === 'auth/email-already-in-use') {
Alert.alert('오류', '이미 사용 중인 이메일입니다. 다른 이메일로 시도해주세요.');
} else if (error.code === 'auth/weak-password') {
Alert.alert('오류', '비밀번호는 6자리 이상이어야 해요.');
} else {
Alert.alert('오류', '회원가입에 실패했어요. 다시 시도해봐요.');
}
}
};
// 로그인 함수: 이메일이랑 비밀번호로 로그인 시도.
const handleLogin = async (email, password) => {
try {
const userCredential = await auth().signInWithEmailAndPassword(email, password);
console.log('로그인 성공:', userCredential.user.email);
// 로그인 성공 후에는 다음 화면으로 넘어가게 했다.
} catch (error) {
console.error('로그인 실패:', error.code, error.message);
if (error.code === 'auth/invalid-email') {
Alert.alert('오류', '이메일 형식이 올바르지 않아요.');
} else if (error.code === 'auth/user-not-found' || error.code === 'auth/wrong-password') {
Alert.alert('오류', '이메일 또는 비밀번호가 일치하지 않아요.');
} else {
Alert.alert('오류', '로그인에 실패했어요. 다시 시도해봐요.');
}
}
};
사용자가 로그인했는지, 아니면 로그아웃했는지에 따라 앱이 다르게 작동해야 했다. onAuthStateChanged는 이 역할을 아주 훌륭하게 해줬다. 앱이 시작될 때, 로그인/로그아웃 할 때, 심지어 인증 토큰이 갱신될 때도 이 함수가 호출됐다. 그래서 나는 이걸 이용해서 사용자 인증 상태에 따라 화면을 분기하는 로직을 만들었다.
import { useEffect, useState } from 'react';
import auth from '@react-native-firebase/auth';
function AuthChecker() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true); // 초기 로딩 상태를 보여주기 위해 만들었다.
useEffect(() => {
// onAuthStateChanged는 인증 상태가 바뀔 때마다 실행된다.
const unsubscribe = auth().onAuthStateChanged((currentUser) => {
setUser(currentUser);
if (loading) {
setLoading(false); // 초기 로딩이 끝나면 상태를 변경한다.
}
// console.log('인증 상태가 변경되었음을 감지했다:', currentUser ? currentUser.email : '로그아웃 상태');
});
// 컴포넌트가 사라질 때 구독을 해제하는 걸 잊지 않았다. (메모리 누수 방지!)
return unsubscribe;
}, []);
if (loading) {
return <SplashScreen />; // 로딩 중에는 스플래시 화면을 보여주는 게 좋다고 생각했다.
}
// 유저가 있으면 로그인 상태, 없으면 로그아웃 상태다.
return user ? <LoggedInApp /> : <AuthScreens />; // 로그인 여부에 따라 다른 컴포넌트를 렌더링했다.
}
// <LoggedInApp />과 <AuthScreens />는 예시로, 실제 앱에서는 해당 컴포넌트를 사용했다.
나는 이걸 이용해서 앱이 처음 시작될 때 스플래시 화면을 띄우고, 그동안 Firebase 인증 상태를 확인해서 사용자가 로그인 상태인지 아닌지에 따라 적절한 화면으로 전환되도록 만들었다. 덕분에 사용자 경험이 훨씬 매끄러워졌다.
이메일 인증은 사용자 계정의 유효성을 확인하는 가장 기본적인 단계라고 생각했다. 이메일 오타를 방지하고, 악의적인 계정 생성을 막는 데 효과적이라서 나는 꼭 이 기능을 넣으려고 노력했다.
import auth from '@react-native-firebase/auth';
import { Alert } from 'react-native';
const sendVerificationEmail = async () => {
const user = auth().currentUser;
if (user) {
try {
await user.sendEmailVerification();
Alert.alert('안내', '인증 메일을 보냈어요! 이메일 함을 확인해주세요.');
} catch (error) {
console.error('이메일 인증 발송 실패:', error);
Alert.alert('오류', '이메일 인증 메일 발송에 실패했어요. 다시 시도해주세요.');
}
} else {
Alert.alert('오류', '로그인 상태가 아니에요.');
}
};
// 사용자가 이메일 인증을 완료했는지 확인하는 방법
const isEmailVerified = auth().currentUser?.emailVerified; // 이 값이 true면 인증 완료된 것!
💡 내가 얻은 팁: 이메일 인증이 완료되기 전까지는 앱의 핵심 기능 사용을 제한하는 게 좋았다. 예를 들어, 인증 완료 전에는 특정 버튼을 비활성화하거나, 인증 완료 페이지로만 강제로 이동시키는 식으로 구현했다. 사용자에게 '인증을 해야만 모든 기능을 쓸 수 있다!'는 것을 명확히 알려주는 게 중요하다고 생각했다.
로그아웃은 간단한 기능이지만, 사용자 데이터를 안전하게 보호하기 위해 중요하다. 나는 로그아웃 시 앱 내에 저장된 사용자 관련 캐시나 상태를 함께 지우는 로직을 추가하려고 노력했다.
import auth from '@react-native-firebase/auth';
import { Alert } from 'react-native';
const handleLogout = async () => {
try {
await auth().signOut();
Alert.alert('안내', '성공적으로 로그아웃되었습니다.');
// 로그아웃 후 로컬 스토리지에 저장된 사용자 데이터, 토큰 등을 지우는 로직을 추가했다.
// (예: AsyncStorage.clear()나 특정 키 제거)
// 그리고 로그인 화면으로 되돌아갔다.
} catch (error) {
console.error('로그아웃 실패:', error);
Alert.alert('오류', '로그아웃에 실패했어요. 다시 시도해주세요.');
}
};
Firebase Auth는 기본 기능 외에도 개발 편의성을 높여주는 유용한 기능들이 많았다. 나도 자주 사용하고 있다.
auth().sendPasswordResetEmail(email)auth().currentUser?.delete()reauthenticateWithCredential 등으로 사용자에게 다시 한번 비밀번호를 입력하게 해서 본인 확인 절차를 거치는 게 안전하다고 생각했다.auth().currentUser?.getIdToken(true)true를 인자로 넘기면 무조건 갱신된 토큰을 가져왔다.로그인/회원가입 플로우는 앱의 첫인상이고, 사용자가 앱을 계속 사용할지 말지를 결정하는 중요한 부분이라고 생각한다. 그래서 나는 항상 UX에 신경을 많이 쓰는 편이다.
| 기능 | 내가 써본 UX 전략 (예시) |
|---|---|
| 회원가입 에러 처리 | - 이메일 중복, 비밀번호 길이/특수문자 조건 같은 건 사용자가 입력하는 즉시 또는 버튼 클릭 직후에 명확하고 친절한 메시지로 알려줬다.\<br>- auth/email-already-in-use 같은 복잡한 에러 코드를 사용자 친화적인 한글 메시지로 바꿔서 보여주는 게 정말 중요했다. |
| 이메일 인증 체크 | - 회원가입 직후에는 "이메일 인증이 필요합니다!"라는 모달이나 별도의 인증 페이지로 이동시켜서 핵심 기능을 잠가버렸다.\<br>- 앱 진입 시 user.emailVerified를 확인해서 인증되지 않았다면 계속 인증을 유도했다.\<br>- 인증 메일 발송 버튼은 여러 번 누르지 못하게 쿨타임을 주거나, 이미 메일이 발송되었다는 알림을 띄워줬다. |
| 자동 로그인 유지 | - 앱 시작 시 스플래시 화면을 띄우고, 그동안 onAuthStateChanged로 로그인 상태를 확인했다.\<br>- 로그인 상태면 바로 메인 화면으로, 아니면 로그인/회원가입 화면으로 자연스럽게 분기 처리해서 사용자가 앱을 매번 다시 로그인하지 않도록 만들었다. |
| 비밀번호 재설정 | - 재설정 메일 발송 후에는 '메일함을 확인해주세요' 같은 명확한 안내를 해주고, 재설정 링크로 이동 후 앱으로 다시 돌아올 수 있도록 딥링크를 활용하는 것도 좋은 방법이었다. |
| 로딩 인디케이터 | - 로그인, 회원가입, 인증 메일 발송 등 네트워크 요청이 필요한 작업 중에는 로딩 스피너를 꼭 보여줬다.\<br>- 안 그러면 앱이 멈춘 것처럼 보여서 사용자가 바로 앱을 꺼버릴 수 있었다. |
Firebase Auth를 사용하면서 내가 가장 중요하다고 생각했던 핵심들을 다시 한번 정리해봤다.
| 항목 | 핵심 키워드 |
|---|---|
| 인증 방식 | 이메일, 소셜 (구글, 애플 등), 익명 로그인 |
| 주요 메서드 | createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut |
| 상태 관리 | onAuthStateChanged (앱 내 인증 상태 변화 감지, 화면 분기) |
| 계정 보안 | sendEmailVerification (이메일 인증), sendPasswordResetEmail (비밀번호 재설정) |
| 나의 노력 | 에러 처리, UX/UI 신경 쓰기! |
🛡️ Firebase Auth, 처음엔 좀 어렵게 느껴질 수도 있지만, React Native 개발자에게는 정말 든든한 도구가 되어준다고 생각한다. 로그인/회원가입은 앱의 첫인상이나 마찬가지니까, 보안은 물론이고 사용자 경험까지 세심하게 고려하는 것이 좋은 앱을 만드는 데 가장 중요하다고 나는 늘 다짐한다. 🔥