티스토리 뷰

흐름

* REDIRECT_URL : 프론트 쪽으로 지정(localstorage:3000/auth/kakao)

  1. 프론트 : 카카오 서버에서 인가코드 받기 (/oauth/authorize) => window.location.href 이용
  2. 프론트 : REDIRECT_URL 통해 인가코드를 받으면 react-router-dom 이용하여 카카오 로그인 처리용 컴포넌트(KakaoAuthHandle)로 이동 => 백엔드로 인가코드와 함께 JwtToken 요청
  3. 백엔드 : 카카오 서버에서 액세스 토큰 받기 (/oauth/token)
  4. 백엔드 : 액세스 토큰으로 카카오 유저 정보 받기 (/v2/user/me) => DB 조회 후 프론트에 JWT Token 전송 (회원 아닐 경우 가입 처리)
  5. 프론트 : JWT Token 받아 로그인 처리 (localStorage 이용)

 

 


1. 인가코드 받기 (프론트 - React)

  • 카카오 서버로 인가코드를 요청하면(1번) → (2~4번 생략) → 카카오 서버는 Redirect URL로 인가코드를 전달(6번)
  • 인가코드 요청 URL : ` https://kauth.kakao.com/oauth/authorize?client_id=$ {CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code`
    • CLIENT_ID : 내 앱의 REST API 키
    • REDIRECT_URL : 인가코드를 받을 백엔드 or 프론트엔드 URL (나는 프론트엔드 URL로 진행)

 

* 로그인 창에서 동의 화면이 뜨지 않음

이미 동의를 했다면 이후엔 동의 화면이 뜨지 않음
-> 동의화면 다시 출력해서 보고 싶으면 카카오 계정 '연결 끊기' 후 시도할 것 (https://devtalk.kakao.com/t/topic/116096)

 

소스 코드

// Login.js

const CLIENT_ID = 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=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code`

// 사이트 내 로그인 페이지에서 '카카오 로그인' 버튼 클릭 시
const clickLoginButton = async () => {
    window.location.href = KAKAO_AUTH_URL
}
  • 인가코드 전달 형식 : Redirect Url에 Query String으로 전달 => {REDIRECT_URL}?code=abc123....

 

2. 토큰 받기 + 프론트에 JWT Token 만들어 전달 (백엔드 - NestJS)

* 토큰을 받아 바로 회원가입 처리 + 프론트에 JWT Token 전달

 

 

 

* 발생했던 오류 코드 : KOE010

=> client_secret 값을 누락하지도, 잘못된 값을 전달하지도 않았을 경우 다음 사항 체크

  • Content-Type : application/x-www-form-urlencoded
  • JSON 아닌 body QueryString 형식으로 전달 (encodeURIComponent 사용)
    • 참고 : https://kakao-tam.tistory.com/66?category=866966

 

* 발생했던 오류 코드 : KOE320

 

소스 코드

// auth.controller.ts

@Get('login/kakao')
async getKakaoUserInfo(
	@Query('code') code: string
) {
    // 1. 카카오 유저 정보 받기(카카오 공식 문서 내용)
    const { uid } = await this.authService.getKakaoUserInfo(code)
    // 2. 받은 유저 정보 이용해 나의 서비스 로그인 하기
    const result = await this.authService.login(uid)
    return result
}
// auth.service.ts

// 카카오 유저 정보 받기(카카오 공식 문서 내용)
async getKakaoUserInfo(code: string) {
    const formUrlEncoded = x =>
      Object.keys(x).reduce((p, c) => p + `&${c}=${encodeURIComponent(x[c])}`, '')

    const GET_TOKEN_URL = 'https://kauth.kakao.com/oauth/token'
    const GET_USER_INFO_URL = 'https://kapi.kakao.com/v2/user/me'
    const GRANT_TYPE = "authorization_code"
    const CLIENT_ID = process.env.KAKAO_REST_API_KEY
    const REDIRECT_URI = process.env.KAKAO_REDIRECT_URL
    const requestBody = formUrlEncoded({
      grant_type: GRANT_TYPE,
      client_id: CLIENT_ID,
      redirect_uri: REDIRECT_URI,
      code,
    })
    
    // 1. 토큰 받기
    const { data } = await axios.post(
      GET_TOKEN_URL,
      requestBody,
    )
    
    // 2. 받은 토큰으로 유저 정보 받기
    const { data: userInfo } = await axios.get(GET_USER_INFO_URL, {
      headers: {
        Authorization: 'Bearer ' + data.access_token,
      }
    })

    return userInfo
}

// 내 서비스 로그인 로직
async login(uid: number): Promise<any> {
    const user = await this.usersService.findOneByUid(uid)

    if(!user) throw new NotFoundException('회원 정보가 존재하지 않습니다.') // => 가입 처리 필요

    const jwtToken = this.getJwtToken(user)

    return {
      status: 200,
      data: { jwtToken, userId: user.id },
    }
}

 

3. 로그인 처리 (프론트엔드 - React)

* 백엔드에서 JWT Token 받아 localStorage에 저장

 

소스 코드

// App.js

const [isLogin, setIsLogin] = useState(false)

useEffect(() => {
    const jwtToken = localStorage.getItem("JWT_TOKEN")

    if(jwtToken) {
      axios.defaults.headers.common['Authorization'] = jwtToken
      setIsLogin(true)
    }
}, [])

return (
    <>
      <BrowserRouter basename={process.env.PUBLIC_URL}>
        <Routes>
            {/* REDIRECT_URL로 설정 */}
            <Route path="/auth/kakao" element={<KakaoAuthHandle setIsLogin={setIsLogin} />}></Route>
      </BrowserRouter>
    </>
);
// KakaoAuthHandle.js

import axios from "axios";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

function KakaoAuthHandle({ setIsLogin }) {
    const navigate = useNavigate()

    const kakaoLogin = async () => {
        const code = new URL(window.location.href).searchParams.get('code')
        const { data } = await axios.get(`${process.env.REACT_APP_API_URL}/auth/login/kakao`, {
            params: { code }
        })
        const { jwtToken } = data.data
        localStorage.setItem("JWT_TOKEN", jwtToken)
        setIsLogin(true)
        navigate("/")
    }

    useEffect(() => {
        kakaoLogin()
    }, [])
}

export default KakaoAuthHandle;

 

 


공식 문서

참고 블로그

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함