개발 일지

카카오로 로그인하기 (JWT 토큰 발급, OAuth)

hou27 2022. 3. 25. 03:17

진행하고 있는 프로젝트에 접근성이 중요해서 카카오톡으로 로그인할 수 있도록 구현했었는데,

내가 짠 구조가 맞는지 의문이 들어 찾아보다가

 

OAuth+Spring Boot+JWT

 

[OAuth + Spring Boot + JWT] 1. OAuth란? 프론트엔드와 백엔드의 역할

OAuth(Open Authorization)란? OAuth는 인증을 위한 프로토콜이다. 다른 인터넷 서비스의 기능을 다른 어플리케이션에서도 사용할 수 있게 해준다. OAuth는 인증(Authentication)과 인가(Authorization)를 모두 포함

velog.io

위 글을 보게 되어 구조를 수정하였다.

 

수정 전의 카카오 로그인 흐름은 아래와 같았다.

 

 

 

근데 

https://developers.kakao.com/

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

가이드를 다시 읽어보다가

 

위 다이어그램을 발견했고,

 

수정 후 diagram

우선 위와 같이 흐름을 수정하였다.

 

Func loginWithKakao

async loginWithKakao({ code }: LoginWithKakaoInput): Promise<LoginOutput> {
    try {
      // get access token
      const formData = {
        grant_type: 'authorization_code',
        client_id: process.env.KAKAO_REST_API_KEY,
        redirect_uri: process.env.REDIRECT_URI_LOGIN,
        code,
        client_secret: process.env.KAKAO_CLIENT_SECRET,
      };
      const {
        data: { access_token },
      } = await axios
        .post(`https://kauth.kakao.com/oauth/token?${qs.stringify(formData)}`)
        .then((res) => {
          return res;
        });

      // get user info
      const { data: userInfo } = await axios
        .get('https://kapi.kakao.com/v2/user/me', {
          headers: {
            Authorization: 'Bearer ' + access_token,
            'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
          },
        })
        .then((res) => {
          return res;
        });

      const name = userInfo.properties.nickname;
      const profileImg = userInfo.properties.profile_image;
      const email = userInfo.kakao_account.email;
      const gender = userInfo.kakao_account.gender;
      const birth = userInfo.kakao_account.birthday;

      const password = // 비밀번호 생성
      let intGender = gender === 'male' ? 0 : 1;

      // check user exist with email
      const { ok: user } = await this.findByEmail({ email });

      // control user
      let createAccountResult;
      if (!user) {
        const { ok } = await this.createAccount({
          name,
          email,
          gender: +intGender,
          password,
          profileImg,
          birth,
        });
        createAccountResult = ok;
      }

      if (user || createAccountResult) {
        return await this.login({ email, password });
      } else {
        return { ok: false, error: "Couldn't create account in try" };
      }
    } catch (e) {
      console.log(e);
      return { ok: false, error: 'Please Refresh and Try One more time' };
    }
  }

backend에서 동작하는 login with kakao 함수이다.

 

// get access token
  const formData = {
    grant_type: 'authorization_code',
    client_id: process.env.KAKAO_REST_API_KEY,
    redirect_uri: process.env.REDIRECT_URI_LOGIN,
    code,
    client_secret: process.env.KAKAO_CLIENT_SECRET,
  };
  const {
    data: { access_token },
  } = await axios
    .post(`https://kauth.kakao.com/oauth/token?${qs.stringify(formData)}`)
    .then((res) => {
      return res;
    });

frontend에서 넘겨준 코드를 통해 access token을 발급받은 후,

 

// get user info
  const { data: userInfo } = await axios
    .get('https://kapi.kakao.com/v2/user/me', {
      headers: {
        Authorization: 'Bearer ' + access_token,
        'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
      },
    })
    .then((res) => {
      return res;
    });

access token을 통해 유저 정보를 가져온다.

// check user exist with email
  const { ok: user } = await this.findByEmail({ email });

  // control user
  let createAccountResult;
  if (!user) {
    const { ok } = await this.createAccount({
      name,
      email,
      gender: +intGender,
      password,
      profileImg,
      birth,
    });
    createAccountResult = ok;
  }

  if (user || createAccountResult) {
    return await this.login({ email, password });
  } else {
    return { ok: false, error: "Couldn't create account in try" };
  }

그 후 이메일로 유저를 확인하여

이미 계정이 있다면 로그인을, 없다면 유저 정보로 계정을 생성한 후 로그인한다.

 

 

이렇게 흐름은 변경하였지만 코드가 섹시하지 못한 것 같아 더 수정해보도록 할 것이다.

또한 현재 token 하나만 반환하고 있는데, 만료 기한을 설정하고 refresh token을 적용하도록 할 것이다.

 


참고자료

 

https://velog.io/@max9106/OAuth