[2차 프로젝트][숙박 플랫폼] 카카오 소셜로그인 (REST API 방식, Redirect URI)

우리는 프론트엔드에서 인가코드와 로그인 토큰을 발급받은 후, 백엔드에 전송해주면 백엔드에서 해당 토큰으로 유저정보를 조회해 JWT토큰을 생성해 프론트에게 넘겨주기로 했다. 이 토큰은 프론트에서 로그인 여부를 확인해 페이지를 리다이렉트하거나 로그아웃, 혹은 백엔드로부터 인증이 필요한 요청을 할 때 사용한다.

인증/인가 과정과 JWT토큰에 대해서는 지난 포스팅에서 정리해두었다.

🔹 사용한 방법

왜 이 방식을 사용했을까?

팝업창을 이용한 방법이 더 쉽겠지만, REST API에 대해 공부하면서 조금이라도 더 사용해보고 싶었다.
공식문서를 읽고 빠르게 적용하는 것 또한 개발자로서 중요한 능력이라고 생각했기 때문이기도 했다.



💎 카카오 인가코드 발급받기

인가 코드 요청의 응답은 redirect_uri로 HTTP 302 Redirect되며, Location에 인가 코드가 담긴 쿼리 스트링(Query String) 또는 에러 메시지를 포함합니다. 사용자가 [취소] 버튼을 클릭한 경우에는 에러 메시지를 담은 쿼리 스트링이 redirect_uri로 전송됩니다.
서비스 서버는 redirect_uri로 받은 요청을 처리해 인가 코드를 얻거나 상황에 맞는 페이지를 보여주도록 처리해야 합니다. 받은 인가 코드는 토큰 받기에 사용합니다.

카카오 디벨로퍼스 사이트에서 등록한 redirect URI 로 리다이렉트 시키면, 해당 URI에서 code 파라미터로 인가코드를 보내준다.

🔹 URL

GET /oauth/authorize?client_id={REST_API_KEY}
     &redirect_uri={REDIRECT_URI}&response_type=code HTTP/1.1
Host: kauth.kakao.com
const REDIRECT_URI = 'http://localhost:3000/signin_kakao';
const KAKAO_AUTH_URL =`
    https://kauth.kakao.com/oauth/authorize
    ?client_id=${API_KEY}
    &redirect_uri=${REDIRECT_URI}&response_type=code
`;

리다이렉트된 페이지의 url창에 다음과 같이 인가코드가 뒤에 code파라미터 값으로 발급된 것을 확인할 수 있다.

http://localhost:3000/users/signin-kakao?code=

이것을 useSearchParams로 인가코드만 받아와 카카오로그인 토큰을 발급받는데 사용하였다.



💎 카카오 로그인토큰 발급받기

공식문서에 작성된 내용은 다음과 같다.

POST /oauth/token HTTP/1.1
Host: kauth.kakao.com
Content-type: application/x-www-form-urlencoded;charset=utf-8
curl -v -X POST "https://kauth.kakao.com/oauth/token" \
 -H "Content-Type: application/x-www-form-urlencoded" \
 -d "grant_type=authorization_code" \
 -d "client_id={REST_API_KEY}" \
 --data-urlencode "redirect_uri={REDIRECT_URI}" \
 -d "code={AUTHORIZE_CODE}"

주의할 점은! content-type이 application/x-www-form-urlencoded라는 것이다. 따라서 body에 전달하는 값은 쿼리스트링 형태여야한다.

(이 부분을 잘 몰라서 해결하는데 시간이 걸렸다.)

const [searchParams, setSearchParams] = useSearchParams();
  const API_KEY = process.env.REACT_APP_KAKAO_API_KEY;
  const CLIENT_SECRET = process.env.REACT_APP_CLIENT_SECRET;

  const getKakaoToken = () => {
    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=${API_KEY}&${searchParams}&client_secret=${CLIENT_SECRET}`,
    })
      .then(res => res.json())
      .then(res => getLoginToken(res.access_token));
  };

💎 발급받은 카카오 토큰 전송 후 JWT 토큰 받기

인증/인가 방식을 포함한 JWT토큰에 대해서 대해서는 별도 포스팅으로 정리해두었다.

  const getLoginToken = kakaoToken => {
    fetch(
      `url`,
      {
        method: 'POST',
        headers: {
          Authorization: kakaoToken,
        },
      }
    )
      .then(res => res.json())
      .then(res => saveLoginToken(res.token));
    goToMain();
  };

💎 로그인 완료 후 토큰 스토리지에 저장, 메인페이지로 이동

백엔드에서 받은 JWT 토큰을 세션스토리지에 저장해 이후에도 다른 페이지에서 로그인 정보가 필요할 경우 사용할 수 있도록 하고, 메인 페이지로 이동시켰다.

  const getLoginToken = kakaoToken => {
    fetch(
      `url`,
      {
        method: 'POST',
        headers: {
          Authorization: kakaoToken,
        },
      }
    )
      .then(res => res.json())
      .then(res => saveLoginToken(res.token));
    goToMain();
  };

  const saveLoginToken = loginToken => {
    sessionStorage.setItem('loginToken', loginToken);
  };

  const goToMain = () => {
    navigate('/');
  };

  return null;
}

export default KakaoLogin;


💎 아쉬운 점 / 리팩토링 계획

로그인이 반드시 성공할 수는 없기 때문에 성공할 경우에만 세션스토리지 토큰 저장 및 메인페이지 이동 액션을 취하고, 에러일 경우에는 별도의 처리가 필요하다. 이 부분은 시간관계상 마무리하지 못해 리팩토링 기간동안 다시 완성할 예정이다.

좋은 웹페이지 즐겨찾기