[Vite + React + Typescript] 카카오로그인 REST API 구현하기

2024. 7. 12. 14:58

이번 사이드프로젝트에서 시간상 로그인을 카카오 로그인만 구현하기로 했다.

예~전에 카카오 로그인은 spring으로 구현해 봤는데 프론트에선 처음이라 내가 해보기로 했다.

 

SDK와 REST API 방식 두 개가 있었는데 확인해보니

 

- REST API : 카카오 로그인 페이지를 먼저 접속한 후, 카카오톡 로그인 버튼을 통해서 카카오톡 앱에서 로그인할 수 있게 제공.

- SDK : 핸드폰에 카카오톡 앱이 설치되어 있다면, 카카오톡 앱을 실행하여 로그인을 할 수 있게 제공. 만약 앱이 설치가 안되어있다면, REST API와 동일하게 로그인 페이지가 나타남.

 

써본 앱 중에서는 지그재그, 오늘의 집 등(인기 많은 대부분의 앱들)이 SDK를 이용하는 것 같고, REST API는 못 찾고 있다가 친구가 알려준 라이프집이라는 앱이 그렇게 사용하고 있는 듯하다.

 

SDK는 순식간에 지나가서 캡쳐는 못했지만 카카오톡 사용하는 유저라면(안사용 하는 사람이 있겠냐만은ㅎㅎ) 너무 편리할 거 같다.

REST API는 아래 사진처럼 뜬다.

 

 

처음엔 REST API로 구현을 다 해놨다가, 

이번 프로젝트는 웹앱 형식이고 추후 앱으로도 생각 중이라 SDK로 변경할까 해서 구현해봤었는데 모바일 테스트도 어렵고, 그냥 추후 리팩토링 할 때 수정하는 걸로😅


앱 키 생성방법은 다루지 않을 예정입니다. (필요하다면 https://nxxrxx.tistory.com/22 여기서 확인!)

 

✔️앱 키는 노출되면 안 되기 때문에 .env파일에 넣어주고 .gitignore에 넣어주기

나는 redirect uri도 같이 넣어줬다.

// .env
# kakao login
VITE_APP_REST_API_KEY={앱 키 입력}
VITE_APP_REDIRECT_URI={Redirect uri 입력} // ex. http://localhost:3000/auth/kakao/callback

 

작업하기 쉽게 config 파일을 만들어 변수로 넣어줬다.

vite는 import.meta~~ 로 import 해 올 수 있으니 참고!

// config
export const KAKAO_CLIENT_ID = import.meta.env.VITE_APP_REST_API_KEY;
export const KAKAO_REDIRECT_URI = import.meta.env.VITE_APP_REDIRECT_URI;
export const KAKAO_BASE_URL = "https://kauth.kakao.com/oauth/token";
export const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${KAKAO_CLIENT_ID}&redirect_uri=${KAKAO_REDIRECT_URI}&response_type=code`;

 

 

로그인 컴포넌트를 만들어 주자

// KakaoLogin.tsx
import { Button } from "components/buttons";
import { KAKAO_AUTH_URL } from "config";

const KakaoLogin = () => {
  const link: string = KAKAO_AUTH_URL;

  const handleLogin = () => {
    window.location.href = link;
  };
  return (
    <div>
      <Button onClick={handleLogin}>카카오 로그인</Button>
    </div>
  );
};

export default KakaoLogin;

위 상황까지가 1번 상황이다. 이제 카카오 로그인 버튼을 클릭하면 2~5번까지가 진행되고,

이제부터 6번을 구현하려고 한다.

 

 

인가 코드를 전달하고(Step 1의 6번), 토큰을 받는 거 (Step 2)까지 한 번에 Auth파일에서 처리하려고 한다.

// Auth.tsx
import axios from "axios";
import { KAKAO_BASE_URL, KAKAO_CLIENT_ID, KAKAO_REDIRECT_URI } from "config";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

const Auth = () => {
  const navigate = useNavigate();
  useEffect(() => {
    const params = new URL(document.location.toString()).searchParams;
    const code = params.get("code"); // 인가 코드
    const GRANT_TYPE = "authorization_code";
    const data = {
      grant_type: GRANT_TYPE,
      client_id: KAKAO_CLIENT_ID,
      redirect_uri: KAKAO_REDIRECT_URI,
      code: code,
    };
	
    // 토큰 발급
    axios
      .post(KAKAO_BASE_URL, data, {
        headers: {
          "Content-type": "application/x-www-form-urlencoded;charset=utf-8",
        },
      })
      .then((res) => {
        console.log("kakao login response", res.data);
        if (res) {
          localStorage.setItem(
            "accessToken",
            JSON.stringify(res.data.access_token)
          );
          localStorage.setItem(
            "refreshToken",
            JSON.stringify(res.data.refresh_token)
          );
          navigate("/");
        }
      });
  }, []);

  return <div>login</div>;
};

export default Auth;

return은 아직 개발 중이라 간단히 login으로 적어놨지만 추후 spinner로 바꿀 예정이다.

인가 코드는 실제로 Redirect uri 뒤에 code= ~~~ 로도 확인할 수 있다.

http://localhost:3000/auth/kakao/callback?code={인가코드}

 

실제로 로그인을 진행하면 이런 response가 오는 걸 확인!

 

그전에 한 가지 더 처리해 줘야 하는 게 Router에 Redirect uri를 타고 들어가서 Auth페이지로 넘어갈 수 있게 route 처리를 해준다.

import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";

import { Layout } from "components";
import * as P from "pages";
import AuthRoute from "./AuthRoute";

interface RouterProps {
  children?: React.ReactNode; 
}

const Router = ({ children }: RouterProps) => {
  return (
    <BrowserRouter>
      {children}
      <Routes>
        <Route element={<Layout />}>
          <Route index element={<P.Login />} />
          <Route path="/auth/kakao/callback" element={<P.Auth />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
};

export default Router;

 

이러면 토큰 받기까지 끝!

 

근데 백엔드 분들께서 "인가코드로 토큰 받고 회원정보 받아오는 거는 서버 쪽에서 처리해서 인가코드만 api로 넘겨달라"는 요청이 있어서 곧 수정해야 할 것 같다🤣