[RN] React Native에서 Firebase Cloud Funtions를 활용한 카카오 커스텀 토큰 로그인

Subin·2023년 9월 3일
5

리액트네이티브

목록 보기
5/13
post-thumbnail
post-custom-banner

💡 본 게시글은 React Native FirebaseFirebase 공식문서의 내용을 참고했습니다.

완성된 코드는 깃허브에서 확인 가능합니다.

개요

Firebase는 여러 소셜 로그인을 지원합니다. 하지만 한국에서 가장 널리 쓰이는 카카오와 네이버는 지원하지 않기에 커스텀 토큰 로그인을 통해 Firebase 소셜 로그인을 하는 것이 목표입니다. 그 과정에서 Cloud Funtions을 사용해 커스텀 토큰을 발급하는 서버 로직을 구현합니다.

준비물

Firebase의 Cloud funtions을 사용해서 카카오톡 커스텀 로그인을 사용하려면 아래 2개의 준비가 필요합니다. 물론 카카오톡 로그인 말고 네이버 로그인과 같은 외부 소셜 로그인도 가능합니다. 하지만 본 게시글에서는 카카오 로그인을 사용합니다.
1. React Native에 Firebase 연동하기
2. React Native 카카오 로그인

Firebase CLI 설정 및 초기화

Firebase CLI 설치

터미널에서 해당 코드를 입력해 글로벌로 Firebase CLI를 설치합니다.

npm install -g firebase-tools

Firebase 로그인

Firebase에 로그인하고 액세스합니다.

firebase login

Functions 초기화

Firebase의 functions를 사용하기 위해 Firebase Functions을 적용할 프로젝트 루트 위치에서 아래의 코드로 초기화합니다.

firebase init functions

그러면 아래와 같이 셋업할 수 있습니다. 저번 게시글에서 Firebase 프로젝트를 생성했으니 Use an existing project를 선택해 생성한 프로젝트를 골라줍니다.

이후에 원하는 셋업으로 골라주면 프로젝트 루트 위치에 funtions 폴더가 생기며 Firebase Funtions을 사용할 준비가 완료됩니다.

카카오 커스텀 토큰 발급 함수 작성

Firebase CLI 설정 및 초기화를 하고 나서 funtions/src/index.ts 파일을 확인하면 샘플 함수가 작성되어 있을 텐데 아래와 같이 커스텀 토큰을 발급하는 함수로 바꿔줍니다.

const functions = require("firebase-functions");
const admin = require("firebase-admin");

const getAdminApp = () => {
  const serviceAccountKey = JSON.parse(process.env.SERVICE_ACCOUNT_KEY || "");

  const adminApp = !admin.apps.length
    ? admin.initializeApp({
        credential: admin.credential.cert(serviceAccountKey),
      })
    : admin.app();

  return adminApp;
};

const getCustomToken = async (email: string, id: string) => {
  const adminApp = getAdminApp();
  const auth = admin.auth(adminApp);
  // 카카오 커스텀 로그인
  const kakaoEmail = `${email.split("@")[0]}@kakao.com`;
  const properties = {
    uid: `kakao:${id}`,
    provider: "KAKAO",
    displayName: email,
    email: kakaoEmail,
  };
  let authUser;
  let newUser = false;
  try {
    // 해당 유저 확인
    authUser = await auth.updateUser(properties.uid, properties);
  } catch (error) {
    // 유저가 없을 시 생성
    if (error.code === "auth/user-not-found") {
      authUser = await auth.createUser(properties);
      newUser = true;
    }
  }
  // 커스텀 토큰 발급
  const firebaseToken = await admin
    .auth()
    .createCustomToken(authUser.uid, { provider: "KAKAO" });
  return { firebaseToken, newUser };
};

exports.customTokenLogin = functions.https.onCall(
  async (data, context) => {
    const { email, id } = data;
    const customToken = await getCustomToken(email, id);
    return customToken;
  }
);

Firebase Admin SDK

위 코드의 SERVICE_ACCOUNT_KEY 값은 파이어베이스 -> 프로젝트 설정 -> 새 비공개 키 생성를 눌러 다운받습니다.

그리고 다운받은 키의 데이터를 json-minify에서 공백을 제거한 뒤 .env파일을 생성해 값을 넣어주면 됩니다.

SERVICE_ACCOUNT_KEY='키값'

마지막으로 firebase.json에 작성한 함수명을 적습니다.

"rewrites": [
      {
        "function": "customLoginAPI"
      }
 ],

Cloud Funtions 배포하기

카카오 커스텀 토큰 발급 함수를 제대로 작성했으면 이제 배포를 할 차례입니다.
Cloud Funtions를 배포하려면 Firebase 요금제를 Blaze로 업그레이드 해줘야 합니다.

이후 아래의 코드를 입력해 배포해 줍니다.

cd functions/
npm run deploy

배포가 성공적으로 완료되었다면 Firebase에서 확인해 줍니다.

제대로 배포가 되었다면 이제 Cloud Funtions를 사용할 준비가 되었습니다.

Cloud Funtions 패키지 설치

React Native에서 Firebase Cloud Funtions를 사용하기 위해 해당 패키지를 설치합니다.

npm

npm install @react-native-firebase/functions

Yarn

yarn add @react-native-firebase/functions

이후 ios를 위해 pod install 필수

cd ios/ && pod install

그 외

로그인을 위한 firebase auth와 더불어 데이터 저장을 위해 firestore도 필요합니다. 만약 준비되지 않았다면 파어이베이스 사이트에서 등록하고 프로젝트에서 설치해 줍니다.

등록


설치

yarn add @react-native-firebase/auth @react-native-firebase/firestore

firebase.ts 파일을 만들어 초기화해줍니다.

firebase.ts
import { firebase } from "@react-native-firebase/auth";
import firestore from "@react-native-firebase/firestore";

// Initialize Firebase
const authService = firebase.auth();
const fireStore = firestore();

export { authService, fireStore };

카카오 커스텀 토큰 로그인

카카오 로그인 버튼에 해당 함수를 작동시킵니다.
로직을 말로 풀어 설명하자면
1. react-native-seoul/kakao-login로 카카오 로그인
2. 작성한 Firebase Funtions 함수인 customTokenLogin를 호출해 커스텀 토큰을 발급받음
3.authService.signInWithCustomToken()로 커스텀 토큰 로그인
4. 만약 신규 유저면 firestore에 신규 유저 정보 저장

신규 유저 정보 저장
const setStoreUserInfo = async (email: string, uid: string) => {
    const userData = {
      displayName: email.split("@")[0],
      email,
      uid,
    };

    // db에 유저 정보 저장
    await fireStore.collection("users").doc(`${uid}`).set(userData);
  };
  
// 카카오 로그인
export const onKakaoButtonPress = async (): Promise<void> => {
  try {
    const token = await login();
    const profile = await getKakaoProfile();
    const userInfoData = JSON.parse(JSON.stringify(profile));
    const { email, id } = userInfoData;
    // 작성한 cloud 함수 호출
    const { data } = await firebase
      .functions()
      .httpsCallable("customTokenLogin")({
      email,
      id,
    });
    const { firebaseToken, newUser } = data;
    // 발급받은 커스텀 토큰으로 파이어베이스 로그인 시키기
    const signInWithCustomTokenResult = await authService.signInWithCustomToken(
      firebaseToken
    );

    if (newUser) {
      const kakaoEmail = `${email.split("@")[0]}@kakao.com`;
      setStoreUserInfo(kakaoEmail, signInWithCustomTokenResult.user.uid); // fireStore에 신규 유저 데이터 저장하는 함수
    }
  } catch (error) {
    console.log(error);
  }
};

이후 로그인에 성공하면 Authentication에 아래와 같이 표기됩니다.

마무리

이렇게 React Native에서 서버 없이 Firebase Cloud Funtions를 활용해서 카카오 커스텀 토큰 로그인을 해봤습니다.
여기서 작성한 커스텀 토큰 로그인 함수는 React Native가 아니더라도 Firebase Funtions을 HTTP로 배포해서 웹에서도 사용할 수 있습니다. 그리고 제공한 샘플 코드는 구현에 초점을 맞춘 것이기에 실제 배포 환경에서는 Firebase의 보안규칙을 신경 써야 합니다.

profile
고양이가 세상을 지배한다.
post-custom-banner

0개의 댓글