React + TypeScript 이용해서 카카오 로그인 구현하기

반응형

React + TypeScript를 사용해서 카카오 로그인을 구현해 봤습니다.

Next.js를 이용해서 개발을 진행하였습니다.

 

카카오 로그인 과정

1. 카카오 SDK 자바스크립트 불러오기

<script src="https://t1.kakaocdn.net/kakao_js_sdk/2.4.0/kakao.min.js"
  integrity="sha384-mXVrIX2T/Kszp6Z0aEWaA8Nm7J6/ZeWXbL8UpGRjKwWe56Srd/iyNmWMBhcItAjH" crossorigin="anonymous"></script>
<script>

2. 카카오 SDK 초기 설정

Kakao.init(JAVASCRIPT_APP_KEY);

3. 로그인 요청

Kakao.Auth.authorize({
   redirectUri: "http://localhost:3000/login",
});

로그인이 성공하게 되면 redirectUri에서 설정한 주소로 코드 값이 옵니다.

ex) http:/// localhost:3000/login?code=12345

4. 코드 값을 보내서 토큰 받아오기

const response = await fetch("https://kauth.kakao.com/oauth/token", {
   method: "POST",
   headers: {
      "Content-type": "application/x-www-form-urlencoded;charset=utf-8",
   },
   body: `grant_type=authorization_code&client_id=${REST_API_KEY}&redirect_uri=http://localhost:3000/login&code=${req.query.code}`,
});

5. 토큰 값 설정하기

Kakao.Auth.setAccessToken(accessToken);

토큰 값을 설정하게 되면 사용자 정보를 가져올 수 있습니다.

6. 사용자 정보 가져오기

Kakao.API.request({
   url: "/v2/user/me",
});

 

위의 일련의 과정을 거쳐서 카카오 로그인이 성공하게 되고, 유저정보를 가져올 수 있습니다.

 

React 코드

저는 Next.js에서 React + TypeScript를 이용해서 구현해 보았습니다.

pages/api/getKakoLogin.ts

Kakao.Auth.authorize 호출 이후 redirect를 통해서 받은 code를 token으로 받는 함수입니다.

import type { NextApiRequest, NextApiResponse } from "next";

const REST_API_KEY = "YOUR_REST_API_KEY";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  if (req.method === "POST") {
    const response = await fetch("https://kauth.kakao.com/oauth/token", {
      method: "POST",
      headers: {
        "Content-type": "application/x-www-form-urlencoded;charset=utf-8",
      },
      body: `grant_type=authorization_code&client_id=${REST_API_KEY}&redirect_uri=http://localhost:3000/login&code=${req.query.code}`,
    });
    const data = await response.json();

    res.status(200).send({ data });
  }
}

 

login/index.tsx

import { Fragment, useEffect, useState } from "react";
import { useRouter } from "next/router";

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

interface IuserInfo {
  nickName: string;
  email?: string;
  profileImagePath?: string;
}

const KAKAO_SDK_URL = "https://developers.kakao.com/sdk/js/kakao.js";
const JAVASCRIPT_APP_KEY = "YOUR_JAVASCRIPT_APP_KEY";

export default function KakaoLogin() {
  const router = useRouter();
  const [code, setCode] = useState<string | string[] | undefined>(undefined);
  const [isLogin, setIsLogin] = useState<Boolean>(false);
  const [userInfo, setUserInfo] = useState<IuserInfo>({
    nickName: "",
  });

  useEffect(() => {
    const script = document.createElement("script");

    script.src = KAKAO_SDK_URL;
    script.async = true;

    document.body.appendChild(script);

    script.onload = () => {
      window.Kakao.init(JAVASCRIPT_APP_KEY);
    };
  }, []);

  async function loginWithKakao() {
    await window.Kakao.Auth.authorize({
      redirectUri: "http://localhost:3000/login",
    });
  }

  useEffect(() => {
    const getToken = async (code: string | string[] | undefined) => {
      const response = await getLoginToken(code);
      return response.data.access_token;
    };
    const setAccessToken = async (accessToken: string) => {
      if (accessToken) {
        if (window.Kakao.Auth) {
          await window.Kakao.Auth.setAccessToken(accessToken);
        }
        setIsLogin(true);
      } else {
        setIsLogin(false);
      }
    };
    const getUserInfo = async () => {
      if (!code) {
        return;
      }

      const accessToken = await getToken(code);
      if (accessToken) {
        await setAccessToken(accessToken);
      }
      if (isLogin) {
        const response = await window.Kakao.API.request({
          url: "/v2/user/me",
        });
        setUserInfo({
          nickName: response.properties.nickname,
          email: response.kakao_account.email,
          profileImagePath: response.properties.profile_image,
        });
      }
      await router.push("/login");
    };

    if (router.query.code !== code) {
      setCode(router.query.code);
    }

    getUserInfo();
  }, [router.query.code, code]);

  async function getLoginToken(code: string | string[] | undefined) {
    const response = await fetch("/api/getKakaoLoginToken?code=" + code, {
      method: "POST",
    });
    return await response.json();
  }

  return (
    <Fragment>
      <h1>Kakao Login</h1>
      <a id="kakao-login-btn" onClick={loginWithKakao}>
        <img
          src="https://k.kakaocdn.net/14/dn/btroDszwNrM/I6efHub1SN5KCJqLm1Ovx1/o.jpg"
          width="222"
          alt="카카오 로그인 버튼"
        />
      </a>
      <h2>{isLogin ? "Success" : ""} </h2>
      <h2>{userInfo.email}</h2>
      <h2>{userInfo.nickName}</h2>
      <img
        src={userInfo.profileImagePath}
        alt="profile image"
        width="250px"
        height="250px"
      />
    </Fragment>
  );
}

 

카카오 로그인 성공 화면

 

728x90
반응형