Firebase로 초간단 인증 구현하기

허지예·2024년 8월 14일
0

개인 프로젝트 기록

목록 보기
14/17

Firebase란~?

Firebase는 Google이 제공하는 애플리케이션 개발 플랫폼이다.

개발자가 고품질의 애플리케이션을 빠르고 쉽게 구축할 수 있도록 돕는 다양한 도구와 서비스를 제공한다.

Firebase는 백엔드 서비스, 데이터베이스, 인증, 호스팅 등을 포함해서 애플리케이션의 전반적인 개발, 출시 운영을 지원하는 포괄적인 솔루션을 제공

  • Firebase Authentication → 지금 쓸 거
    • 사용자의 로그인과 인증을 관리하는 서비스다.
  • Cloud Firestore
    • 실시간 데이터베이스로, 클라우드 기반 NoSQL 데이터베이스.
  • Cloud Functions for Firebase
    • 서버 리스 방식으로 애플리케이션의 백엔드 로직을 작성할 수 있는 서비스, 특정 이벤트(데이터베이스 변경, 인증 이벤트) 자동으로 실행되는 함수를 작성할 수 있다
  • Firebase Cloud Messaging (FCM)
    • 푸시 알림을 클라이언트 애플리케이션에 전송할 수 있는 서비스.

Firebase 인증을 활용한 사용자 인증 과정

간편한 Firebase 서비스를 활용해서 사용자 인증 과정을 구현해보자.

위에 과정을 거치기로 했다.

  1. client에서 인증 API를 호출한다.
  2. Firebase에서는 인증 정보를 확인하고 인증 토큰을 전달한다.
  3. 발급 받은 토큰을 브라우저 쿠키에 저장한다.
    • onIdTokenChanged()를 사용해 토큰이 갱신되면 자동으로 업데이트 해준다.
  4. client에서 server에 인증이 필요한 API를 보낼 때 쿠키에 저장한 토큰을 함께 보낸다.
  5. server는 건네받은 토큰을 검증하고 나서 API 로직을 진행한다.

1. Firebase Console에서 프로젝트를 생성하고, 설정을 해준다.

  • Project에서 Authentication 설정에서 Sign-in providers에 Email/Password 방식을 사용 설정해준다.

  • Project Setting에 General에 아랫 쪽 App 부분에서 SDK setup and configuration를 확인해준다.

그 파일을 복사해서 firebase.ts로 프로젝트에 넣어준다.

// firebase.ts
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
  measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};

const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);

나는 조금 변형해서 config 값들을 env에 넣어줬고, 인증 때 사용하기 위한 auth을 export해줬다.

2. 인증 API 사용하는 로직 작성

  • token을 쿠키에 관리하는 로직

    // tokenManager.ts
    import { deleteCookie, setCookie } from 'cookies-next';
    import { NextOrObserver, User, onIdTokenChanged } from 'firebase/auth';
    
    import { auth } from 'firebase';
    
    export const TOKEN_COOKIE_NAME = 'idToken' as const;
    
    export const TOKEN_COOKIE_OPTIONS: OptionsType = {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      maxAge: 60 * 60,
      sameSite: 'strict',
    } as const;
    
    // 리스너가 여러 개 등록이 되는 일이 없도록...
    let unsubscribeTokenChangedListener: (() => void) | undefined;
    
    const saveIdToken = async (user: User | null) =>
      user && setCookie(TOKEN_COOKIE_NAME, await user.getIdToken(), TOKEN_COOKIE_OPTIONS);
    
    export async function sessionLogin(user: User) {
      await saveIdToken(user);
    
      unsubscribeTokenChangedListener?.();
      unsubscribeTokenChangedListener = onIdTokenChanged(auth, saveIdToken as NextOrObserver<User>);
    }
    
    export async function sessionLogout() {
      await auth.signOut();
    
      unsubscribeTokenChangedListener?.();
      deleteCookie(TOKEN_COOKIE_NAME);
    }
  • firebase를 활용해 인증하는 API (예외 처리는 다음에)

    import { deleteCookie, setCookie } from 'cookies-next';
    import {
      browserLocalPersistence,
      browserSessionPersistence,
      createUserWithEmailAndPassword,
      sendEmailVerification,
      setPersistence,
      signInWithEmailAndPassword,
    } from 'firebase/auth';
    
    import { auth } from '@/shard/lib/firebase';
    import handleFirebaseAuthError from '@/shard/lib/firebase.errorhandle';
    
    import { sessionLogin, sessionLogout } from 'tokenManager';
    
    export type AuthDTO = {
      email: string;
      password: string;
    };
    
    export async function signup({ email, password }: AuthDTO) {
        const { user } = await createUserWithEmailAndPassword(auth, email, password);
        await sessionLogin(user);
        sendEmailVerification(user);
    }
    
    export async function login({ email, password }: AuthDTO) {
        const { user } = await signInWithEmailAndPassword(auth, email, password);
        await sessionLogin(user);
    }
    
    export async function logout() {
        await sessionLogout();
    }
profile
대학생에서 취준생으로 진화했다가 지금은 풀스택 개발자로 2차 진화함

0개의 댓글

관련 채용 정보