카카오 로그인 API - HTTP 프로토콜 이해하기(Node.js)

장현수·2023년 2월 27일
0
post-thumbnail

카카오 로그인 API

가장 오랜기간 붙잡았던 카카오 로그인 API이다. 처음 사용해보는 만큼 이해하기도, 적용하기도 힘들었다. 내가 사용했으면서도 제대로 이해하지 못해 아쉬움이 많다. 이번 기회에 반드시 카카오 로그인 API를 씹어먹고자 한다...!

먼저 로그인 과정은 kakao developers 페이지에 잘 나와있다.(https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api)
과정을 먼저 숙지하고 들어가보자.

(1) 인가코드 요청하기

카카오 서버에서 인가코드를 받아야 사용자 정보에 접근할 수 있는 엑세스 토큰, 엑세스 토큰을 갱신해줄 리프레쉬 토큰을 발급받을 수 있다. 본 프로젝트에서는 클라이언트단에서 인가코드를 요청해 받아왔다.

import React from 'react';
import Kakao from '../assets/kakao.svg';

export default function KakaoAuth({ btnText }) {
  const REST_API_KEY = process.env.REACT_APP_REST_API_KEY;
  const REDIRECT_URI = process.env.REACT_APP_REDIRECT_URI;
  const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code`;

  const kakaoLogin = () => {
    window.location.href = KAKAO_AUTH_URL;
  };
  return (
    <>
      <button type="button" className=" user-primary-btn" onClick={kakaoLogin}>
        <div className="flex justify-center">
          <img src={Kakao} width="20px" alt="kakao" className="mr-4" />
          {btnText}
        </div>
      </button>
    </>
  );
}

클라이언트 단에서는 로그인 버튼 클릭 시 인가 코드를 받기 위한 카카오 서버 링크로 이동하도록 했다.
이는 인가코드를 통해 카카오 서버에 사용자 정보에 접근할 수 있는 토큰을 발급받기 위함이다.

링크 구성은

GET /oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code HTTP/1.1
Host: kauth.kakao.com

위와 같다. 하지만 네트워크 지식이 0인 나는 전혀 이해할 수 없었다.

이것을 활용하기 위해 URL구조를 공부해야 했다.

역시 갓활코딩님께서 친절히 강의하신 영상이 있었다. (https://youtu.be/Zhbvui_T9VY)

이 간단한 URL구조를 토대로 kakao developers에서 제공한 REST API 코드를 다시 보자.
둘째 줄의 HOST는 host = domain이름, 즉 인가코드를 요청할 카카오 서버의 도메인라는 것을 알 수 있다.
통신규칙은 http/1.1 방식으로, host는 카카오에서 제공한대로 적용해보면

https://kauth.kakao.com

까지 알 수 있었다.
?뒤에는 쿼리 스트링으로, 서버에 데이터를 전달할 수 있다. 값과 값은 &으로, 값의 이름과 값은 =으로 구분한다.
그리고 그동안 axios요청했던 방식을 생각해보면,

GET /oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code HTTP/1.1
Host: kauth.kakao.com
  1. https://kauth.kakao.com + (GET뒤의 긴 주소)로 GET요청을 보낸다.
  2. 뒤의 긴 주소 중 ?뒷부분은 쿼리스트링이다. 즉 쿼리 스트링에 client_id, redirect_uri, response_type을 담아 서버에 보내는 요청이다.
  3. client_id에는 카카오 로그인 API 등록 시 받은 REST API KEY 값을, redirect_uri에는 등록 시 내가 설정한 로그인 redirect_uri 값을 넣어준다.

정리해보면,

https방식으로 kauth.kakao.com이라는 주소(도메인)에 있는 Kakao Auth Server의 /oauth/authorize라는 폴더(path)로 접근해서 client_id, redirect_uri, response_type 라는 데이터를 전달하는 GET 요청

인 것이다.

(2) 인가코드 받아오기

자, 그리고 다시 공식 문서를 살펴보면



여기까지 읽고 나니 위의 GET요청 URL마지막 부분의 response_type=code가 무엇인지 알게 되었다. 인가코드 받기 요청이 성공하면 redirect uri로 쿼리스트링에 code=인가코드가 담겨 올 것이고, 실패하면 error=에러코드 와 같이 담겨 올 것이다.


클라이언트 App.js를 보면 위와 같이 redirect uri로 path가 설정된 페이지가 있다. 로딩페이지다. 실제로 테스트해보면, 동의하고 시작하기를 눌렀을 때 바로 로딩페이지로 넘어간다. redirect_uri는 서비스 이용 동의 후 로드할 페이지의 주소라는 것을 알게 되었다.

Kakao 컴포넌트의 axios요청은 다음과 같다.

 const navigate = useNavigate();
  let params = new URL(document.URL).searchParams;
  let code = params.get('code');

  const getAccessToken = () => {
    axios
      .post('http://localhost:5000/api/getkakao', { authcode: code })
      .then((res) => {
        if (res.status === 200) {
          const { accessToken } = res.data;
          localStorage.setItem('accessToken', accessToken);
          setTimeout(() => {
            navigate('/account');
          }, 1500);
        } else {
          alert('로그인에 실패하였습니다.');
          navigate('/login');
        }
      });
  };

  useEffect(() => {
    getAccessToken();
  }, []);

쿼리 스트링의 data를 뽑아오는 법은 생활코딩의 다음 강의 있다.(https://youtu.be/_bh8ztMJIPE)
클라이언트 팀원분께서 생활코딩과는 다른 방법으로 인가코드를 받아오셨기에 이 코드를 분석해보려고 한다.

document.URL로 현재 문서의 URL을 문자열로 받아 new URL()로 새로운 URL객체에 담고, searchParams로 파라미터 값을 받아오고 있다.

여기서 의문이 생긴다.
요청을 보낼 때 쿼리스트링으로 보냈는데, 왜 searchParams를 사용하는 걸까?

찾아보니 리액트 라우터에서는 쿼리 스트링 해석하는 모듈을 제공하지 않아서 URLSearchParams를 사용하는 것이 좋다고 한다.(https://youtu.be/gJlz5HUoJtY - 제로초)

쿼리스트링과 파라미터의 차이는 https://velog.io/@jcinsh/Query-string-path-variable 이 글에서 잘 정리해놓은 것 같으니 참고하면 좋을 것 같다.

urlSearchParams.get("parameterName");은 parameterName으로 조회되는 첫번째 값을 return한다. code로 조회되는 첫번 째 값, 즉 code에 담겨오는 값 인가코드이다.

그리고 POST요청으로 서버에 인가코드를 authcode에 담아 보내고 있다.
그럼 다음 단계는 이 인가코드를 가지고 Kakao Auth Server에 토큰을 요청하는 것이다. 이 부분은 서버단에서 진행했다.

(3) 토큰 받기

서버에서는 토큰 발급을 위해 Kakao Auth Server에 axios요청을 보내고 있다.
클라이언트에서 보내준 인가코드는 req.body.authcode에 잘 담겨오고 있다. 인가코드를 code라는 변수에 새로 담아준다.

  let get_token = await axios({
    url: `${KAKAO_TOKEN_URL}?grant_type=${GRANT_TYPE}&client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&code=${code}`,
    method: 'post',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
  });


카카오 공식문서를 보고 아까 배운 것을 바탕으로 생각해보자.
"HTTP/1.1방식으로 kauth.kakao.com 도메인의 /oauth/token 폴더에 POST요청을 보낸다!"
즉, 'https://kauth.kakao.com/oauth/token'으로 POST요청을 보내는 것.

그런데 밑에 Content-type이라는 처음 보는 녀석이 등장했다.

찾아보니 Content-Type은 HTTP 메시지(요청과 응답 모두)에 담겨 보내는 데이터의 형식을 알려주는 헤더라고 한다. 헤더는 또 뭘까?

결론적으로 https://youtu.be/TwsQX1AnWJU www시리즈 영상을 통해 HTTP 프로토콜에 대해 알게 되었다.

HTTP 요청 프로토콜의 구조는 다음과 같다.

이것을 예시를 통해서 보면 더 와닿는다. 아래 예시는 Body가 없는 경우다.

추가로, Request Line의 구조와 응답 프로토콜의 Response Line의 구조도 알아보자.
[Request Line의 구조]

이제 여기까지 보고 카카오 로그인 REST API를 다시 보면, 카카오에서 제공해 준 게 요청 프로토콜이었구나~ 하는 확신이 들거다.
그리고 이 Request Line 안의 URI의 구조는 위에서 생활코딩 강의를 통해 배운 그것이다.

[Response Line의 구조]


요청 프로토콜을 공부했으니 응답 프로토콜의 구조도 이해할 수 있게 되었다.

다시 돌아와서 카카오 REST API를 보자.

이제, 이게 뭔지 알게됐다!
토큰을 요청하는 HTTP요청 프로토콜이고, 요청 메소드는 POST, Request Line, Headers가 적혀있다.
Host는 URI의 구조 중 https:// 프로토콜 뒤에 오는 부분이고, 본래 IP주소:포트의 형태이지만 위의 요청 프로토콜에는 도메인이 적혀있다. 실제로는 이 도메인으로 접근하면 DNS에서 해당하는 IP주소:포트로 연결해준다.

이걸 AXIOS 요청으로 작성하는 법은 axios 공식문서를 참고했다. (https://axios-http.com/kr/docs/req_config)

{
  // `url`은 요청에 사용될 서버 URL입니다.
  url: '/user',

  // `method`는 요청을 생성할때 사용되는 메소드입니다.
  method: 'get', // 기본값

  // `headers`는 사용자 지정 헤더입니다.
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  },

엄청나게 긴 코드 중 요청 프로토콜에 있는 것들만 남겼다.

이 요청의 응답을 다음과 같이 친절히 알려준다. 이것들을 data객체에 담겨있으므로 res.data.값 과 같이 접근하면 된다.

바로 여기서 엑세스 토큰과 리프레시 토큰을 가져올 수 있는 것이다.

(4) 사용자 정보 가져오기

이제 거의 다 왔다. 내가 필요한 것은 사용자 이메일과 닉네임이다. 토큰을 사용해서 이 두가지 값을 가져와야 한다.

사용자 정보 가져오기 API이다. 이제 이제 뭔지 해석하는건 식은 죽 먹기다.

바로 axios 요청으로 바꿔보자.

axios({
	url: 'https://kapi.kakao.com/v2/user/me',
	method: 'POST', 
    headers: { 
    	'Authorization': 'Bearer ${ACCESS_TOKEN}/KakaoAK ${APP_ADMIN_KEY}',
    	'Content-Type':'application/x-www-form-urlencoded;charset=utf-8' 
        }
})

Content-Type은 공통헤더, Authorization은 요청헤더다.(https://www.zerocho.com/category/HTTP/post/5b3ba2d0b3dabd001b53b9db)


응답은 토큰을 가져올 때와 마찬가지로 위에서 필요한 정보를 가져오면 된다.

모모아 프로젝트는 JWT를 이용한 자체 로그인 기능도 있기 때문에 카카오 토큰은 사용자 정보를 가져올 때만 사용해줬다.

정리

카카오 로그인 API만이 아니라 그때그때 필요한 지식들도 찾고 배우느라 정신없는 흐름이었다. 그렇지만 HTTP에 대해 알게되니 axios요청을 보낼 때도 훨씬 더 풍부한 지식으로 이해하고 보낼 수 있게 되어 뿌듯할 따름이다.

  1. HTTP 요청 프로토콜은 Request Line, Headers, 공백, Body로 구성되어있다.
    Request Line은 요청방식, URI, HTTP 버전으로 구성되어있다. HTTP/1.1 버전은 Headers를 반드시 포함한다.
    URI는 프로토콜, Host, Path, Query-String으로 이루어져 있다.
    Host는 IP주소:포트 이고 보통 도메인으로 쓰인다. 도메인으로 요청을 보내면 DNS에서 IP주소:포트로 요청을 보낸다.
    Path는 파일 경로이다. 서버의 해당 파일로 접근하면 브라우저에서 화면으로 그 파일이 보이는 것이다.
    Query-String에는 데이터를 담아 보내줄 수 있다.

  2. 카카오 로그인과 마찬가지로, 보안을 위해 로그인을 할 때에는 토큰을 사용한다. 엑세스 토큰이 실질적으로 사용자를 인증하는 역할을 하지만 보안에 취약하기 때문에 자주 바꿔줘야 한다. 따라서 토큰 시간을 짧게 주고 리프레시 토큰으로 갱신해 사용한다.

2차 프로젝트 직전, 리액트 개인프로젝트를 할 때 네이버 로그인 API를 사용하려 했으나 실패했던 경험이 생각난다.
카카오 로그인 API를 하면서 제대로 파고들어 이해하고 말겠다는 일념으로 임했다. 이제 네이버 로그인 API를 빨리 개인프로젝트에 적용해보고 싶은 자신감도 생겼다.
프로젝트 시간이 부족해 카카오 로그인 API 하나 적용하는데 많은 시간을 쓰는게 아까울 때도 있었지만, 덕분에 HTTP 프로토콜의 요청 - 응답을 더 알게되어 값진 시간이었다.

profile
개같이 발전하자 개발

0개의 댓글