카카오 로그인 구현기 TOKEN 발급 FEAT: 빨안쓰

걍걍규·2023년 11월 7일
0
post-thumbnail

이번 팀프로젝트에서 카카오 API를 많이 사용하게 됐다

그래서 혼자 연습하던 도중 꽉막힌 부분을 해결하여 급히 쓴다

내가 개발하던 영화앱에 카카오로그인을 추가해볼 겸 연습하고 있는데

카카오 공식문서의 이해하기 탭을 보면 이런 그림이 있고
내가 지금까지 구현한 것은 토큰 발급 까지이다.

앞으로는 발급한 토큰으로 사용자의 정보를 받아온 후 나의 DB에 저장해주는 등의 일을 해주어야겠다

클라이언트

인가코드를 받은 후 서버로 넘겨주는 작업을 한다

<FormButton submitFunc={isKakaoLogin} text={'카카오 로그인'} />

기존에 만들어 둔 버튼에 함수를 등록해준다

  const isKakaoLogin = () => {
    const redirect_uri = 'http://localhost:3000/auth'; //Redirect URI
    // oauth 요청 URL
    const kakaoURL = `https://kauth.kakao.com/oauth/authorize?client_id=${KAKAOREST}&redirect_uri=${redirect_uri}&response_type=code`;
    window.location.href = kakaoURL;
  };

kakao에서 제공하는 url에 client_id와 redirect_url을 넣어 get요청을 보낸다
(단순히 url로 이동하는 것은 get요청과 동일하다)

위에 필요한 값은 여기서


여기까지 와서 나의 애플리케이션을 추가하거나 선택한다
추가할때 항목은 대충 입력해도된다

redirect_url

client_id

REST API키

확인하고 이제 버튼을 누른다

그러면 우리가 설정해놓은 url로 이동하는데 그 곳에서 로그인을 하겠냐는 페이지를 보여주고 수락한다면

redirect_url로 브라우저는 설정해놓은 곳으로 이동하게 된다

그 페이지는 아마 비어있거나 할텐데 나같은 경우에는

<Route path="/auth" element={<KakaoLogin />} />

redirect_url의 경로로 가서 보여줄 페이지를 하나 만들어주었다

import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { userInfoState } from '../recoilAtoms';
import { useRecoilState } from 'recoil';
import axios from 'axios';

export default function KakaoLogin() {
  const [userInfo, setUserInfo] = useRecoilState(userInfoState);
  const navigate = useNavigate();

  const PARAMS = new URL(document.location).searchParams;
  const KAKAO_CODE = PARAMS.get('code');

  console.log(KAKAO_CODE);

  const getAccessToken = async () => {
    if (isToken) return; // Return early if fetching

    try {

      const response = await axios.post(
        'http://localhost:4000/auth/kakao/login',
        {
          authorizationCode: KAKAO_CODE,
        },
        {
          headers: {
            'Content-Type': 'application/json',
          },
        },
      );

    } catch (error) {
      console.error('Error:', error);
      setIsToken(false); 
    }
  };


  return <div>Loding..</div>;
}

페이지의 코드이고 여기까지 인가코드를 받아오는 과정이다

인가코드는 카카오에서 우리의 url로 전달해주니 확인바란다

http://localhost:3000/auth?code=cxckzfq18ZbHAZK9TjVn8ZE17pCAQYK_NkSf0fWL4Yh94qIsDo4o8sKJuPAKPXLqAAABi6d_8lXE017PSiBv1Q

이런식으로 ..!
url에서 code를 추출하여 서버로 전송하면 클라이언트측의 1차 업무는 끝이난다

서버에선 이제 그 인가코드를 받아 토큰을 발급받을 것이다

서버

서버에서 해주여아 할 것은 일단은..
1. 토큰 발급
2. 발급한 토큰을 이용하여 유저의 정보를 가져온다

업무쪼개기

토큰 발급!

POSTMAN

카카오에서 요구하는 헤더와 바디를 설정해주자

client_secret은 따로 생성해두지 않았다면 스킵
만약 이미 생성했다면 꼭 ! 추가해주자

headers


Content-Type : application/x-www-form-urlencoded (고정)

body

code : 인가코드
grant_type : authorization_code (고정)
client_id : 위에있는거
redirect_url : 위에있는거

이렇게 토큰이 발급되는 것을 확인할 수 있다

유의할 점은 인가코드가 유효한지 확인해보아야한다

data: {
  error: 'invalid_grant',
  error_description: 'authorization code not found for code=C048j_fFOKbh6ec4Vn1CjIQylCg1OzH2bOEPaObOVihVcr_hK3Ev9LcvAHgKPXUZAAABi6eS7_kq17LwdM8QAg',
  error_code: 'KOE320'
}

이런 에러를 만났다면 인가코드를 다시 발급받은 후에 확인해보자

CODE

router.post('/kakao/login', getToken, getUserInfo);

나의 경우 auth를 라우터로 지정해 주었고
클라이언트 측에서 auth/kakao/login으로 요청 시 위에 코드가 실행될 것이다

getToken과 getUserInfo를 미들웨어로 설정해주었다

const getToken = async (req, res, next) => {

  const CLIENT_ID = '님의 클라이언트ID';
  const REDIRECT_URL = '님의 리다이렉트URL:';
  const code = req.body.authorizationCode;
  //client 측 참고바람

  const kakaoTokenUrl = `https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URL}&code=${code}`;
  
  //QueryString 형식으로 보내주어야 한다

  const kakaoHeader = {
    'Content-type': 'application/x-www-form-urlencoded;charset=utf-8',
  };

  await axios
    .post(kakaoTokenUrl, {
      headers: kakaoHeader,
    })
    .then((res) => {
      console.log('good');
      console.log(res.data);
    })
    .catch((err) => {
      console.log('err');
      console.log(err);
    });
};

트러블 홈런

해당 에러를 만났을 경우 체크해야할 점을 말해주겠다
1. 위 설명대로 client_secret값을 생성해놓고 추가하지 않은 경우
단순히 body에 추가해주면 될 듯 하다
나의 경우 원래는 client_secret값을 생성도 해 놓았고 body에 추가하였으나 그것이 해결되지 않았다
그리고 생성했던 client_secret값을 삭제하고 다시 해보아도 동일한 에러가 계속 나왔고
이 에러를 마주친 대부분이 1번의 경우는 아닐 것이라는 생각이 든다

2. body데이터를 쿼리스트링으로 변환하여 전달해보자
구글링을 해본 결과 해당 방법으로 해결하신 분의 사례를 보았고 나도 적용해 보았다

  const requestData = {
    grant_type: 'authorization_code',
    client_id: '님의 ID',
    redirect_uri: '님의 URL',
    code: req.body.authorizationCode,
  };

  const queryStringBody = Object.keys(requestData)
    .map((el) => encodeURIComponent(el) + '=' + encodeURI(requestData[el]))
    .join('&');

위 함수를 이용하면 데이터를 쿼리스트링의 형태로 보낼 수 있다

  await axios
    .post(kakaoTokenUrl, {
      headers: kakaoHeader,
    }, {
    queryStringBody
  })
    .then((res) => {
      console.log('good');
      console.log(res.data);
    })
    .catch((err) => {
      console.log('err');
      console.log(err);
    });
grant_type=authorization_code&client_id=님의ID&redirect_uri=님의URL&code=e7Av1NbGITfwnOMMMTKNTXzQ4hMSPmVTl6kvChVrVcQj_fl_EK1b7OHf9kEKKwymAAABi6eX8VnUNEQ5evY1pg

이런 모양으로 만들어서 전송된다
나는 물론 이것으로도 해결하지 못했다

참고 링크 : https://kdinner.tistory.com/92

3. GET요청을 하듯 URL에 QueryString형태로 데이터를 전송해보자
내가 해결한 방법이다

const kakaoTokenUrl = `https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URL}&code=${code}`;

body 데이터를 담은 url변수를 만든 후에

  await axios
    .post(kakaoTokenUrl, {
      headers: kakaoHeader,
    })
    .then((res) => {
      console.log('good');
      console.log(res.data);
    })
    .catch((err) => {
      console.log('err');
      console.log(err);
    });
};

따로 데이터를 추가하지 않고 url만을 이용하여 post요청을 했다 그 결과 ..
업로드중..
토큰이 웃으며 나를 반겨주었다

의문

  1. 2번 방법과 어떤 차이가 있는지 정확히는 모르겠으나
    url 자체에 데이터를 담아서 보내는게 맞는 방법이라는 생각이 들었다
  2. 포스트맨에서는 쉽게 되는 것이 javascript 코드로 가공하는 것이 생각보다 오래걸렸다 나의 실력에 대한 의문 ..

배운 점

  1. 다양한 방법으로 axios 요청하는 방법을 보았다. 나는 너무 한가지 방법만 고집해 왔다 카카오 전용 axios 모듈을 만들어 활용하는 방법을 리펙토링으로 적용시킬 것이다!
  2. API를 사용할땐 문서를 꼼꼼히 읽는 것이 중요하다 구글링도 좋지만 문서와 반복해서 번갈아 가며 확인하다보면 더욱 빨리 해답을 찾을수 있을 것 같다!
profile
안녕하시오?

0개의 댓글