본문 바로가기
이론/Frontend

Next.js 13에서 Kakao 로그인 처리하기 with Firebase (2)

by 유세지 2023. 11. 2.

 

 

들어가며

지난 글에서는 카카오 API를 이용하기 위해 프로젝트에 환경 설정을 하고,

카카오 서버와 통신까지 진행해보았습니다.

 

이번 포스팅에서는 받아온 데이터를 토대로 Firebase와 연동하여 저장하는 과정을 알아보겠습니다.

 

 

 

Firebase 연동

Firebase를 이용하기 위해서는 먼저 프로젝트를 등록하는 절차가 필요합니다. Firebase Console에 접속합니다.

 

 

Firebase Console 접속 화면

 

 

최근 프로젝트의 "프로젝트 추가" 버튼을 눌러 새 프로젝트를 만듭니다.

 

 

새 프로젝트 생성 과정

 

 

구글 애널리틱스는 반드시 설정할 필요는 없습니다.

그냥 넘어가셔도 구현에 문제는 없으니 구성하지 않으셔도 좋습니다.

 

 

생성된 프로젝트의 모습

 

 

프로젝트가 생성되면 위와 같은 화면으로 들어올 수 있습니다.

바로 우리 서비스에 Firebase를 추가해봅시다.

 

우리는 웹 서비스이므로, </> 버튼을 눌러 다음으로 진입하겠습니다.

 

 

앱을 등록하고, SDK를 발급받습니다.

 

 

프로젝트에서 사용할 앱을 등록하고, 잠시 기다리면 SDK의 발급이 완료됩니다.

<script> 태그 방식을 사용해도 되지만, 여기에서는 모듈을 사용하겠습니다.

 

아래에 안내되는 방법대로 모듈을 설치하여 프로젝트에 Firebase SDK를 추가합니다.

꼭 npm을 사용하지 않아도 괜찮습니다. 사용중인 패키지 매니저의 모듈 설치 방법대로 라이브러리를 설치해줍니다.

 

모듈 설치가 끝났다면, config 파일을 생성하여 프로젝트에 적용합니다.

저는 src/firebase 경로에 config.js 파일로 넣어주었습니다.

 

// Import the functions you need from the SDKs you need
import { initializeApp, getApps } from "firebase/app";

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,
};

// Initialize Firebase
const firebaseApp =
  getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];

export default firebaseApp;

 

이전 글에서 한 것처럼 보안이 중요한 SDK는 Next.js 환경 변수로 따로 관리해주겠습니다.

여기에 getApps를 통해 서비스가 실행된 뒤 initializeApp이 실행될 수 있도록 합니다.

 

Next.js 에서의 세팅은 마쳤으니, 다시 Firebase Console로 돌아옵니다.

 

 

Firebase Console의 모습

 

 

아래 Authentication - 사용자 인증 및 관리 카드를 눌러 인증 메뉴로 들어갑니다.

 

 

Authentication - Sign-in method 메뉴

 

 

시작하기를 눌러 Sign-in method 메뉴로 들어오면 인증 방법을 추가하는 화면이 나타납니다.

기본 제공업체의 이메일/비밀번호 버튼을 눌러줍니다.

 

 

이메일/비밀번호 사용 설정을 활성화하기

 

 

이메일/비밀번호의 사용 설정을 활성화시키고, 저장을 눌러줍니다.

저장소는 마련되었으니 이제 Firebase로 요청을 보내볼까요?

 

 

 

Next.js에서 Firebase로 요청 보내기

 

Firebase의 회원가입에는 firebase/authcreateUserWithEmailAndPassword 메서드를 이용합니다.

config.js에서 구성해두었던 auth 정보를 가져와서 메서드에 함께 실어 보내줍니다.

 

import firebaseApp from "src/firebase/config";
import { createUserWithEmailAndPassword, getAuth } from "firebase/auth";

const auth = getAuth(firebaseApp);

interface UserAccount {
  email: string;
  password: string;
}

async function signUp({ email, password }: UserAccount) {
  let result = null;
  let error = null;
  
  try {
    result = await createUserWithEmailAndPassword(auth, email, password);
  } catch (e) {
    error = e;
  }

  return { result, error };
}

export default function Home() {
  return (
    <main className={styles.container}>
      <div className={styles.introduction}>
        <h5>안녕하세요! 링꾹입니다.</h5>
        <p>링꾹을 이용하시려면 로그인이 필요합니다.</p>
      </div>
      <button onClick={() => signUp({ email: "test@test.com", password: "testpwd" })}>
        <Image
          src="/kakao_login.png"
          alt="Login with Kakao"
          width={300}
          height={45}
          priority
        />
      </button>
    </main>
  );
}

 

 

firebase/auth의  createUserWithEmailAndPassword 메서드를 사용하면 새 유저정보를 등록할 수 있습니다.

우선은 임시로 테스트 데이터를 넣어서 Firebase에 요청이 가는지만 확인해봅니다.

 

 

test 데이터가 성공적으로 들어왔습니다.

 

 

 

 

Firebase와의 통신은 문제 없이 이루어졌습니다.

이제 테스트 데이터 대신 카카오 API에서 받은 값을 넘겨주면 되겠네요.

카카오 API의 응답을 받을 페이지에서 데이터를 가공하여 넘겨봅시다.

 

 

const getResponse = async (code: string) => {
  try {
    const responseParams = {
      grant_type: "authorization_code",
      client_id: process.env.NEXT_PUBLIC_KAKAO_JS_KEY || "",
      REDIRECT_URI: "http://localhost:8080/kakao",
      code: code,
    };

    const responseQueryString = new URLSearchParams(responseParams).toString();

    const response = await fetch(
      `https://kauth.kakao.com/oauth/token?${responseQueryString}`,
      { method: "POST" }
    );
    const jsonResponseData = await response.json();
    const { access_token } = jsonResponseData;

    const kapiParams = {
      secure_resource: "true",
      property_key: '["kakao_account.email"]',
    };

    const kapiQueryString = new URLSearchParams(kapiParams).toString();

    const kapiData = await fetch(
      `https://kapi.kakao.com/v2/user/me?${kapiQueryString}`,
      {
        method: "GET",
        headers: { Authorization: `Bearer ${access_token}` },
      }
    );

    const jsonKapiData = await kapiData.json();
    const { email, id } = jsonKapiData;

    if (!email) {
      throw new Error("Invalid user");
    }

    return { email, id };
  } catch (e) {
    console.log(e);
  }
};

 

 

Kakao API로부터 code를 받아 responseParams에서 파라미터 정보를 구성해줍니다.

그 뒤, 구성한 파라미터 정보를 https://kapi.kakao.com/v2/user/me에 함께 넘겨 필요한 데이터를 받아옵니다.

여기서는 kapiParamsproperty_key에 구성했던 유저의 이메일 정보가 되겠습니다.

 

⚠ 주의
유저의 정보를 받아오려면 해당 정보에 대한 유저의 동의가 필요합니다.
카카오 개발자 페이지에서 비즈 앱 등록을 마치면 동의를 받을 수 있습니다.

 

비즈 앱 등록 후 필수항목 체크 시 로그인 화면

 

 

 

마지막으로 결과값으로 받은 email을 동일한 방식으로 Firebase에 넘겨주면 끝입니다.

 

const auth = getAuth(firebaseApp);

async function signUp({ email, id }: UserAccount) {
  let result = null;
  let error = null;

  try {
    result = await createUserWithEmailAndPassword(
      auth,
      email,
      id
    );
    alert("회원가입 완료");
  } catch (e) {
    error = e;
    if (error instanceof Error) {
      if (error.message === "Firebase: Error (auth/email-already-in-use).") {
        await login({ userId });
      } else {
        alert(error);
      }
    }
  }

  return { result, error };
}

async function login({ email, id }: UserAccount) {
  let result = null;
  let error = null;

  try {
    result = await signInWithEmailAndPassword(
      auth,
      email,
      id
    );
    alert("로그인 완료");
  } catch (e) {
    error = e;
    if (error instanceof Error) {
      console.log(error.message);
    }
  }

  return { result, error };
}

 

 

회원가입에 사용했던 API인 createUserWithEmailAndPassword에 각각 auth, email, id를 넘겨줍니다.

여기서 id는 회원 고유의 식별자인데, 다른 유저들과 겹치지 않는 유일한 값이어서 패스워드 대신으로 사용될 예정입니다.

그냥 사용하기가 꺼려지신다면, 이메일을 인자로 해시 처리를 더해주시면 좋을 것 같네요.

 

이미 등록된 계정이라면 Firebase: Error (auth/email-already-in-use). 에러가 발생합니다.

에러 처리를 통해 이 경우 로그인에 사용되는 API인 signInWithEmailAndPassword 를 대신 사용해주시면 됩니다.

 

 

import { useRouter } from "next/navigation";

export default function Kakao() {
  const router = useRouter();

  useEffect(() => {
    const code = new URL(window.location.href).searchParams.get("code");

    if (!code) return;

    async function login(code: string) {
      const { email, id } = await getResponse(code);
      const { result, error } = await signUp({ email, id });

      router.push("/");
    }

    login(code);
  }, [router]);

  return <p>redirect...</p>;
}

 

 

useEffect 훅을 통해 컴포넌트가 mount되면 로그인/회원가입이 실행되도록 해줍니다.

이후 페이지 이동에는 next/navigationuseRouter 훅을 이용해줍니다. (App Router 한정)

 

 

성공적으로 데이터 입력

 

 

Firebase를 확인해보면, 카카오에서 받은 데이터도 잘 들어갔고,

 

 

로그인 완료

 

 

 

계정이 있는 경우 로그인으로 처리도 잘 되고 있습니다.

 

이렇게 Kakao API와 Firebase를 이용해 Next.js 에서 구현하기가 모두 끝났습니다.

 

 

마치며

혼자서는 처음해보는 OAuth연동이었는데, 생각보다 자료도 많고 공식 문서가 잘 되어있어 쉽게 할 수 있었습니다.

 

여담으로 이전에는 반드시 서버를 거쳐야 Kakao API를 사용할 수 있었다는데,

현재는 제한이 풀려 문제없이 사용이 가능해졌습니다. 클라이언트만으로 해결할 수 있게 되다니 굉장히 편리하네요.

 

Next.js에서 Firebase와 Kakao API를 사용하시려는 분들께 이 글이 도움이 되길 바랍니다.

긴 글 읽어주셔서 감사합니다.

 

 

반응형

댓글