카카오 로그인 구현

PRB·2023년 10월 13일
post-thumbnail

1. 배경

사이드 프로젝트에 일반 로그인을 먼저 구현한 후, 소셜 로그인(카카오 로그인)을 추가하게 되었다. 이 과정에서 카카오 로그인 직접 구현 방식과 Next.js + next-auth를 이용한 방식의 차이를 비교해보기 위해 직접 구현 방식을 선택하였다.

2. 카카오 로그인 과정


카카오 로그인은 프론트엔드와 백엔드 중 어디서 처리하느냐에 따라 구분되는데, 나는 프론트엔드(Next.js) 에서 대부분의 과정을 처리하고, 회원 여부 확인만 백엔드로 위임하는 구조로 구현했다.

a.사용자가 카카오 로그인 클릭

사용자가 카카오 로그인 버튼을 클릭

const handleSignWithKaKao = () => {
  const kakao = kakaoInit();
  kakao.Auth.authorize({
    redirectUri: `${process.env.NEXT_PUBLIC_APP_HOST_NAME}/callback/kakao/authorize`,
  });
};

b.프론트 -> 카카오 인가서버 카카오 로그인 화면 요청

프론트에서 카카오 인가 서버로 로그인 요청을 보낸다. 이때, 리다이렉트 URI는 카카오 디벨로퍼스 콘솔에도 등록되어 있어야 한다.

const handleSignWithKaKao = () => {
    const kakao = kakaoInit();
  // 카카오 인가 서버로 인가 코드 요청
    kakao.Auth.authorize({
      redirectUri: `${process.env.NEXT_PUBLIC_APP_HOST_NAME}/callback/kakao/authorize`,
    });
  };

c. 사용자 -> 인가서버 아이디,비번, 동의 체크 완료

사용자가 카카오 로그인 화면에서 아이디/비밀번호 입력 및 동의 항목을 체크한다.

d. 인가서버 -> 사용자 인가코드 반환

카카오 인가 서버는 인가 코드를 발급하고, 사전에 등록한 redirectUri로 리다이렉트한다.

e. 프론트 -> 인가서버 인가코드 넘김

리다이렉트된 프론트에서는 URL에서 인가 코드를 추출하고, 이를 사용해 카카오 인가 서버에 Access Token을 요청한다.

async function fetchAccessToken(code: string): Promise<string> {
  const config = {
    headers: {
      "Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
    },
  };

  const data = new URLSearchParams();
  data.append("grant_type", "authorization_code"); // authorization_code로 고정
  data.append("client_id", KAKAO_APP_KEY); // 앱 REST API 키
  data.append("redirect_uri", `${process.env.NEXT_PUBLIC_APP_HOST_NAME}/callback/kakao/authorize`); // 인가 코드를 전달받을 서비스 서버의 URI
  data.append("code", code); // code로 고정

  try {
    const response = await axios.post("https://kauth.kakao.com/oauth/token", data, config);
    return response.data.access_token || "";
  } catch (error) {
    console.error("Failed to fetch access token:", error);
    return "";
  }
}

export const getServerSideProps: GetServerSideProps<AuthorizeProps> = async (context) => {
  const code = Array.isArray(context.query.code) ? context.query.code[0] : context.query.code || "";
  const accessToken = await fetchAccessToken(code);

  const res = await fetchUserFromKakao(accessToken);

  return { props: { userInfo: res.data } };
};

f. 인가서버 -> 프론트 카카오 토큰 반환

카카오 인가 서버는 인가 코드가 유효하면 Access Token을 반환한다.

g. 프론트 -> 리소스서버 토큰 넘김

발급받은 Access Token을 사용해 사용자 정보를 요청한다.

export const getServerSideProps: GetServerSideProps<AuthorizeProps> = async (context) => {
  const code = Array.isArray(context.query.code) ? context.query.code[0] : context.query.code || "";
  
    // 인가 코드를 사용하여 접근 토큰을 가져옴
  const accessToken = await fetchAccessToken(code);

    // 접근 토큰을 사용하여 사용자 정보를 가져옴
  const res = await fetchUserFromKakao(accessToken);

  return { props: { userInfo: res.data } };
};

h. 리소스서버 -> 프론트 사용자 정보 반환

카카오 리소스 서버는 사용자 정보를 프론트엔드에 응답한다.

i. 프론트 -> 백 사용자 식별

받은 사용자 정보를 기반으로, 백엔드에 사용자 존재 여부를 확인 요청한다. 이미 가입된 사용자라면 로그인 처리하고, 아니라면 회원가입 후 로그인 처리한다.

const Authorize = ({ userInfo }: AuthorizeProps) => {
  useEffect(() => {
    signInOrSignUpKakao();
  }, []);

  const signInOrSignUpKakao = async () => {
    const res = await authApi.kakaoLogin(userInfo.id);

    if (res.message === "OK") {
      window.location.assign(`${process.env.NEXT_PUBLIC_APP_HOST_NAME}/explore`);
    }
  };

  return <h2>로그인 중입니다..</h2>;
};

3. 미 해결 과제

현재, 카카오 로그인을 통해 회원가입하는 경우 닉네임, 관심사, MBTI 등의 추가 정보 입력 과정이 누락되어 있는 문제가 있다. 백엔드에서 임의의 기본값을 넣고, 사용자가 나중에 수정할 수 있도록 처리하고 있다.

향후 계획

카카오 로그인 후, 추가 정보 입력 페이지로 이동

입력된 추가 정보와 카카오 로그인 정보를 통합

통합된 정보를 기반으로 회원가입 처리
profile
사용자 입장에서 사용자가 원하는 것을 개발하는 프론트엔드 개발자입니다.

0개의 댓글