[React] 카카오 로그인 구현하기 - REST API

Isabel·2022년 5월 10일
28

지금 진행하고 있는 프로젝트에서 카카오 로그인과 구글 로그인을 진행하기로 하였다. 먼저 카카오 로그인에 대해 정리하면서 진행해보려고 한다. 아, 그리고 이 글은 프론트엔드의 입장에서 작성된 글이다.

카카오 API를 사용할 때에는 sdk 방식과 REST API 방식이 있는데 프론트에서 모두 해결할 것이 아니고 프론트에서 로그인 요청을 하고 백엔드에서 토큰을 받아 처리할 것이었기 때문에 REST API 방식으로 진행하기로 하였다.

기능 소개 - by 카카오 developers

참고
카카오 로그인은 카카오계정으로 다양한 서비스에 로그인할 수 있도록 하는 OAuth 2.0 기반의 소셜 로그인 서비스입니다.

카카오 로그인 사용 시, 서비스는 서비스 ID 및 비밀번호를 입력받고 검증하는 과정을 직접 구현하지 않고도 사용자에 대한 인증인가를 간편하고 안전하게 처리할 수 있습니다. 사용자는 카카오 로그인이 적용된 서비스에 카카오톡 또는 카카오계정 ID와 비밀번호로 손쉽게 로그인할 수 있습니다.

서비스는 카카오 플랫폼을 이용하기 위해 서비스 정보를 카카오디벨로퍼스(이하 개발자 웹사이트)에서 애플리케이션(이하 앱)으로 등록해야 합니다. 그리고 앱에 서비스 이용을 위해 필요한 권한을 나타내는 동의 항목을 설정해야 합니다. 카카오 로그인을 통해 사용자는 앱 설정의 동의 항목에 대한 사용자 동의를 거쳐 서비스에 로그인할 수 있습니다.

카카오 로그인 완료 시 토큰이 발급됩니다. 토큰은 사용자를 인증하고 카카오 API 호출 권한을 부여하는 액세스 토큰(Access Token)와 액세스 토큰을 갱신하는 데 쓰는 리프레시 토큰(Refresh Token) 두 가지입니다. OpenID Connect를 사용할 경우, 사용자 인증 정보를 담은 ID 토큰이 함께 발급됩니다.

서비스 가입 시에는 인증과 인가 외에도 이용약관과 같이 사용자 동의가 필요한 사항들이 있습니다. 카카오 로그인의 확장 기능인 비즈니스 솔루션 카카오싱크를 도입하면, 카카오 로그인 시 사용자에게 이용약관 동의와 카카오톡 채널 추가까지 함께 요청할 수 있습니다.


인증과 인가

인증과 인가를 간편하게 한다는데 그러면 인증과 인가는 무엇일까?

인증은 ID와 비밀번호로 사용자 신원을 확인하는 것을 의미한다. 로그인을 하게 되면 그 해당 회원이 누구인지를 가려낼 수 있게 되고 이러한 과정에서 카카오에서는 각 사용자를 식별할 수 있는 고유한 회원번호 제공한다.

인가는 우리 프로젝트 팀으로 하여금 사용자 개인정보와 같은 자원(Resource)에 대한 접근 권한 획득하게 해주는 것이다. 사용자가 동의를 함으로써 사용자 정보나 기능에 대한 접근 권한을 개발자에게 부여하게 된다.
해당 권한은 카카오 로그인 시 발급되는 토큰에 같이 부여되며, 토큰을 사용해 해당 사용자에 대해 다양한 카카오 API를 요청할 수 있게 된다. 우리는
카카오 API를 통해 카카오 플랫폼에 저장된 사용자 정보를 제공받거나, 특정 기능이나 동작을 요청할 수 있게 된다.

따라서 인증은 사용자에게 우리 사이트 회원인지 확인 후에 우리 앱을 사용할 수 있게 해주는 것이고, 인가는 우리 팀으로 하여금 사용자의 정보를 이용하거나 동작을 요청하게 하는 것이라고 이해할 수 있다.


카카오 로그인 단계

카카오 로그인은 3가지 단계로 진행된다.

Step1. 카카오 로그인

  1. 서비스 > 카카오 인증 서버 : 인가 코드 발급을 요청
  2. 카카오 인증 서버 > 사용자 : 인증을 요청
    사용자 인증 성공 시,
  3. 카카오 인증 서버 > 사용자 : 동의 화면(서비스 앱의 이용관련 동의 항목)을 출력합
  4. 사용자 : 필수 동의 항목에 동의하고 로그인을 요청
  5. 카카오 인증 서버 : 인가 코드(Authorization Code)를 발급해 서비스 앱에 등록된 Redirect URI로 전달
  6. 서비스 > 카카오 인증 서버 : 전달받은 인가 코드로 토큰을 요청, receive

Step2. 회원 확인 및 서비스 가입

  1. 서비스 앱 > 카카오 API 서버 : 카카오 로그인으로 발급받은 토큰을 통해 사용자 정보 가져오기를 요청
  2. 카카오 API 서버 : 사용된 토큰의 유효성을 검증하고, 요청을 처리
  3. 카카오 API 서버 > 서비스 앱 : 사용자 정보 제공
  4. 서비스 서버 : 제공받은 사용자 정보로 해당 사용자가 서비스에 회원 가입되어 있는지 확인
  • 이미 가입된 사용자: Step 3의 서비스 로그인 단계로
  • 아직 회원 가입되지 않은 사용자: 카카오에서 제공받은 사용자 정보로 서비스 데이터베이스에 회원 가입 처리

Step3. 서비스 로그인

  1. 서비스 서버 > 서비스 클라이언트 : 해당 사용자의 로그인에 대한 Session 발급
  2. 서비스 클라이언트 : 전달받은 서비스 세션으로 로그인 완료 처리하고, 사용자를 로그인된 서비스 화면으로 이동시킴

우리 팀은 카카오에서 전달해주는 액세스 토큰에서 얻은 정보를 가지고 백엔드에서 jwt 토큰을 만들어서 일반 회원가입 할 때처럼 전달받아 회원 가입을 하는 방식으로 진행하기로 하였다. ( ID토큰은 발급받지 않기로 했다. )

또한 웹으로 진행하기 때문에 카카오톡을 통해서가 아닌 카카오 계정을 통해서 로그인 하게 될 것이다.

자, 이제 시작해보자.

1. Kakao Developers에 등록하기

앱 프로젝트 등록

내 계정에 우리 프로젝트인 'Chorok'을 등록하고 플랫폼을 Web으로 설정하였다.

카카오 로그인 활성화

카카오 로그인 페이지로 가서 비활성화 되어있던 상태를 활성화로 바꿔주었다.

카카오 로그인 동의항목 설정

그 다음으로 이용 동의 항목을 설정해야 하는데 우리 앱에서는 많은 정보가 필요치는 않아서 필수 요소인 닉네임을 필수 동의 항목으로, 선택사항인 프로필 사진을 선택 동의 항목으로 설정하였다.


2. 인가 코드 요청

Request

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

고객이 버튼을 클릭하면 서비스 클라이언트에서 서비스 서버로 카카오 로그인을 요청하면 서비스 서버에서 GET방식으로
/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code HTTP/1.1 주소로 요청하여 인증 코드를 받을 수 있다.

위 주소와 아래 파라미터 설명을 보면
파라미터로 client_id와 redirect_uri, response_type은 필수값으로 요청시에 같이 보내야 하고 해당 키의 값들은 REST_API_KEY, REDIRECT_URI, REDIRECT_URI 인 것이다.
나머지 state, prompt, nonce는 필수 파라미터는 아니다.

REST_API_KEY

API키는 처음에 developers에 앱을 등록하면 발급받게 된다. 그 값을 적어주면된다.

Redirect_URI

Redirect URI는 반드시 프론트엔드에서 접근할 수 있는 Host로 지정해주어야 한다고 한다. (http://localhost:3000)
Redirect URI에서 인가 코드를 전달받고 넘기는 등의 작업이 이루어져야 하는데 프론트엔드가 접근할 수 없는 Host로 지정하게 되면 접근자체가 막히기 때문이다.
우리팀의 Redirect_URI는 'http://localhost:3000/auth/kakao/callback'으로 정하였다.

//OAuth.js
const REST_API_KEY = "~~";
const REDIRECT_URI =  "http://localhost:3000/auth/kakao/callback";

export const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code`;

//Login.js
import {KAKAO_AUTH_URL} from '../../~~';
 <Button href={KAKAO_AUTH_URL}>카카오로 로그인하기</Button>

타단~
로그인 창에서 '카카오로 로그인하기' 버튼을 클릭하면 아래와 같은 화면이 나타난다. (카카오 계정에 로그인되어있는 경우)

여기에서 동의하고 계속하기를 누르면 빈화면과 함께 주소창에 기~~~ㄴ 인가코드가 불려온다.

Step1의 인가코드 요청이 끝났다.

3. 백엔드로 인가코드 넘겨주기

1. 파라미터의 값 꺼내오기

window.location.href로 현재 주소창의 주소값을 불러올 수 있다.

new URL 객체에 매개변수로 현재 주소값을 넣으면 아래와 같은 값을 얻을 수 있다. search에 보면 파라미터인 코드 값이 들어있는 것을 확인할 수 있었다.

위에서 사용한 new URL 객체에서 searchParams객체의 get메소드를 사용하여 'code'키의 값을 얻어올 수 있다.

이걸 코들 정리하면 아래와 같다.

//현재 윈도우 창의 주소값 불러옴
const href = window.location.href;
//현재 url의 파라미터를 가져옴
let params = new URL(window.location.href).searchParams;
//params에 저장된 파라미터 안에서 'code'의 값을 가져옴
let code = params.get("code");

그러면 이걸 어느 컴포넌트에서 진행을 해야하느냐.
Kakao.js라는 파일에서 중간 화면단을 만들어 주었다.
여기에서 인가코드를 받아오고, 고객에게는 잠시만 기다려 달라는 문구를 넣어 보여주기로 하였다. 그리고 백엔드로 코드를 보내줄 dispatch도 여기에서 만들어 주었다.

//Kakao.js
import React from "react";
import { useDispatch } from "react-redux";
import { Container, Grid, Text } from "../Elements";
import { actionCreators as userActions} from "../Redux/Modules/User";

const Kakao = (props) => {
    const dispatch = useDispatch();

    const href = window.location.href;
    let params = new URL(document.URL).searchParams;
    let code = params.get("code");

    React.useEffect(async () => {
        await dispatch(userActions.kakaoLogin(code));
    }, []);

    return (
    
        <Container>
            <Grid>
                <Text>잠시만 기다려 주세요! 로그인 중입니다.</Text>
            </Grid>
        </Container> 
    )

}

export default Kakao;

화면에서 이걸 보여주기 위해서 App.jsx에서 Route를 걸어주었다.

//App.jsx
<Route path="/auth/kakao/callback" component={Kakao} />

이제 정말로 인가 코드를 백엔드로 보내주자.

2. 백엔드로 인가 코드 보내기

user.jsx(user정보를 담아두는 리덕스 스토어)에서 axios를 활용하여 백엔드로 보내줄 것이다. 인가코드를 백엔드로 보내줄 때는 post방식이 아니고 쿼리스트링으로 보내주어야 한다고 한다.
받아올 때처럼 url파라미터로 코드를 넘겨준 뒤, get방식으로 토큰과 user정보를 얻어오기로 하였다.

//api.js
kakaoLogIn:(code) => api.get(`/auth/kakao/callback?code=${code}`, {
  }),

3. Token 받아오기

//user.jsx
// 액션 
const SET_USER = "SET_USER";
// 액션 생성
const setUser = createAction(SET_USER, (user) => ({ user }));
// 초기값
const initialState = {
  user: null,
  isLogin: false,
}
//middelware
const kakaoLogInDB = (code) => {
  return function (dispatch, getState, {history}){
    userAPI
      .kakaoLogIn(code)
      .then((response) => {
        console.log(response);
        sessionStorage.setItem('Token', response.data.token);
        localStorage.setItem('username', response.data.username);
        dispatch(setUser({
          username: response.data.username,
          nickname: response.data.nickname,
          profileImgUrl: response.data.profileImgUrl
        }))
        history.replace('/home');
      })
      .catch((error) => {
        console.log("error: ", error);
        window.alert('로그인에 실패하였습니다. ')
        window.replace('/');
      })
  }
}
//reducer
export default handleActions(
  {
    [SET_USER]: (state, action) => produce(state, (draft) => {
      draft.user = action.payload.user;
      draft.isLogin = true;
    })
  }, initialState
)

const actionCreators = {
  setUser,
  kakaoLogInDB,
}

export { actionCreators };

세션스토리지와 로컬스토리지에 사용자의 정보를 저장하고, redux store에도 고객의 정보를 저장해주었다.

완성!!!!

짞짞짞ㅉ깎ㅉ깎

4개의 댓글

comment-user-thumbnail
2022년 8월 14일

카카오 로그인 API에 대해서 제일 설명 잘한 글 같습니다.
도움 많이됐습니다. 감사합니다.!

1개의 답글
comment-user-thumbnail
2023년 10월 9일

혹시 redux toolkit 에 어떻게 코드 작성하셨는지 물어봐도 될까요 ㅠㅠㅠㅠㅠ??

1개의 답글