[Next js + Typescript] Kakao Login 구현하기

5

정 말 애를 많이 먹었다 ㅜ 나와 같은 사람들이 고생할까봐 잘 정리해놓으려고한다.

kakao developers 에서 앱 키 받고 edirect uri 등록하는건 다른곳에도 엄청 많이 나와있으니 생략하겠당!
궁금하신 분은 여기로!

아무리 독스를 찾아보고 해도 next js 에 처음 해보는거라 어떻게 해야할지 막막했다 ㅜ ㅜ

먼저, 프론트만으로 구현할지? 프론트+백엔드로 구현할지를 정해야한다.

나는 프론트 + 백엔드를 선택했다.

왜냐면 카카오 로그인을 하는 사람이 우리 유저 테이블에 있는지 확인하려면 어차피 우리측 서버를 거쳐야하기 때문이당. 애초에 안되는거였는데 프론트에서만 하려고 끙끙댄 내 자신..ㅠ

이제부터 해결 과정을 설명할건데, 해당 독스와 함께 기재하려고 한다! 독스를 보고 어떻게 해석하고 어떤게 추가로 필요했는지 등을 알려드리면 더욱 도움이 될 것 같아서이다 ㅎ (오지랖)

1. Javascript SDK 추가하기

카카오 API를 쓰려면 SDK를 추가해줘야한다.
참조한 DOCs
위 문서에 나온 것처럼 아래 스크립트를 추가해줘야한다.

<script src="https://developers.kakao.com/sdk/js/kakao.js"></script>

넥스트 구조가 낯선 나는 이걸 도대체 어디에? 넣어야하는가? 가 매우 혼란스러운 부분이었다^^

Next js 의 구조상 이렇게 최상단 Head 부분에 추가해줘야하는 script 들은 document.tsx 에 추가해주어야한다! 아래와 같이 말이다.

import Document, { Html, Head, Main, NextScript } from 'next/document';

import { AppConfig } from '@/utils/AppConfig';

// NextScript가 _app.tsx를 송출한다.
// Need to create a custom _document because i18n support is not compatible with `next export`.

class MyDocument extends Document {
  render() {
    return (
      <Html lang={AppConfig.locale}>
        <Head>
          <script src="https://developers.kakao.com/sdk/js/kakao.js"></script>
        </Head>
        <body className="min-h-screen bg-gray-800">
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

이렇게 script 를 추가했는데, 에러가 뜨더라

(property) JSX.IntrinsicElements.script: DetailedHTMLProps<ScriptHTMLAttributes<HTMLScriptElement>, HTMLScriptElement>

External synchronous scripts are forbidden. See: https://nextjs.org/docs/messages/no-sync-scriptseslint(@next/next/no-sync-scripts)

이걸 해결하고 싶어서 next script 를 쓰는등 난리를 쳤지만, 아직 해결하지 못해서 lint disable을 걸어놓았다.

/* eslint-disable @next/next/no-sync-scripts */

다음ㅇㅔ 고쳐줄게... 여튼 이게 SDK 추가는 잘 된것이다!!

2. 초기화

초기화를 하라는데...
카카오에서 하라는 초기화 독스

도대체가 넥스트 타입스크립트에는 어떻게 적용하라는건지 모르겠었다ㅠㅠ

이걸 안하고 Kakao.Auth 이렇게 독스대로 쓰면

kakao is not defined

라는 문구를 무지 많이 볼 수 있다 ^^

이를 해결하기 위해 app.tsx 에 아래와 같이 코드를 추가해주었다.

import { useEffect } from 'react';

import { AppProps } from 'next/app';
import { SWRConfig } from 'swr';

import '../styles/global.css';

declare global {
  interface Window {
    Kakao: any;
  }
}

const App = ({ Component, pageProps }: AppProps) => {

  useEffect(() => {
    window.Kakao.init(process.env.KAKAO_KEY);
  }, []);

  return (
    <SWRConfig>
      <Component {...pageProps} />
    </SWRConfig>
  );
};

export default App;

이렇게 app 최상단에 useEffext 로 init을 해주면 된다. 난 여기저기서 쓰기 때문에 최상단에 넣어주었다.
이때 KEY는 env에 넣어서 쓰면되고, Javascript KEY를 써야한다!! (REST API KEY 아님!!)

declare global {
  interface Window {
    Kakao: any;
  }
}

이 부분은 window 안에 Kakao라는 객체가 있다고 미리 알려주는 것이다. 이로 인해 이제 더이상 Kakao가 누군지 몰라여 하지 않는다 호호 전역으로 window를 정의해줘야한다니 넥스트 너 정말 ^^^;;

3. 화면에 렌더링하기

난 기존 있던 로그인 화면에 버튼을 아래와 같이 추가했다.
샘플 독스 보고 변형했음

  function loginFormWithKakao() {
    Kakao.Auth.loginForm({
      success(authObj) {
        getKakao(authObj.access_token);
      },
      fail(err) {
        console.log(err);
      },
    });
  }
  
  return (
  <button onClick={loginFormWithKakao}>
  <img
    src="//k.kakaocdn.net/14/dn/btroDszwNrM/I6efHub1SN5KCJqLm1Ovx1/o.jpg"
    width="222"
    alt="카카오 로그인 버튼"
  />
</button>
)

렌더 부분에 버튼 넣어주고, 난 팝업을 뜨게 하려하는거기 때문에 loginForm을 써줬다.

4. 서버 통신

api 요청하는 부분은 언제냐면,
프론트에서 카카오 토큰 받아옴 -> back 에 요청
이다. 그래서 간단하게 다음과 같이된다.

export async function getKakao(accessToken: string): Promise<any> {
  const payload = {
    kakaoToken: accessToken,
  };
  try {
    const data: any = await poster('/auth/kakao', payload);
    return data.kakaoProfile;
  } catch (error) {
    return defaultUser;
  }
}

poster 는 본인이 원래 쓰던것을 쓰면 된다. 궁금하신분은 댓글을 남겨주세요!

📍 주의: 백엔드가 아닌 프론트에서 api를 요청하면 CORS 에러가 난다.

REST API DOCS

급하게 짜느라 any도 많고 정리가 덜 되었지만 업데이트 하는대로 포스팅도 업데이트하겠다!

우당탕탕 카카오 로그인 구현이 V1 완성,,

참고문헌
https://yong-nyong.tistory.com/16
https://han-py.tistory.com/417?category=931233
https://docs.strapi.io/developer-docs/latest/developer-resources/content-api/integrations/next-js.html#get-request-your-collection-type

---추가---
로그인 전 후 user 불러오는 것 처리가 따로 필요할땐

const { mutateUser } = useUser();

이렇게 useUser 안에 mutate 함수를 빼서
적재적소에 쓰면 된다! (user 정보 업데이트가 필요할때 hooks 에)

profile
𝙸 𝚊𝚖 𝚊 𝗙𝗘 𝚍𝚎𝚟𝚎𝚕𝚘𝚙𝚎𝚛 𝚠𝚑𝚘 𝚕𝚘𝚟𝚎𝚜 𝗼𝘁𝘁𝗲𝗿. 🦦💛

1개의 댓글

comment-user-thumbnail
2023년 2월 14일

poster에 axios.post를 저장해두셨나요?

답글 달기