이번 팀프로젝트에서 카카오 API를 많이 사용하게 됐다
그래서 혼자 연습하던 도중 꽉막힌 부분을 해결하여 급히 쓴다
내가 개발하던 영화앱에 카카오로그인을 추가해볼 겸 연습하고 있는데
카카오 공식문서의 이해하기 탭을 보면 이런 그림이 있고
내가 지금까지 구현한 것은 토큰 발급 까지이다.
앞으로는 발급한 토큰으로 사용자의 정보를 받아온 후 나의 DB에 저장해주는 등의 일을 해주어야겠다
인가코드를 받은 후 서버로 넘겨주는 작업을 한다
<FormButton submitFunc={isKakaoLogin} text={'카카오 로그인'} />
기존에 만들어 둔 버튼에 함수를 등록해준다
const isKakaoLogin = () => {
const redirect_uri = 'http://localhost:3000/auth'; //Redirect URI
// oauth 요청 URL
const kakaoURL = `https://kauth.kakao.com/oauth/authorize?client_id=${KAKAOREST}&redirect_uri=${redirect_uri}&response_type=code`;
window.location.href = kakaoURL;
};
kakao에서 제공하는 url에 client_id와 redirect_url을 넣어 get요청을 보낸다
(단순히 url로 이동하는 것은 get요청과 동일하다)
여기까지 와서 나의 애플리케이션을 추가하거나 선택한다
추가할때 항목은 대충 입력해도된다
REST API키
확인하고 이제 버튼을 누른다
그러면 우리가 설정해놓은 url로 이동하는데 그 곳에서 로그인을 하겠냐는 페이지를 보여주고 수락한다면
redirect_url로 브라우저는 설정해놓은 곳으로 이동하게 된다
그 페이지는 아마 비어있거나 할텐데 나같은 경우에는
<Route path="/auth" element={<KakaoLogin />} />
redirect_url의 경로로 가서 보여줄 페이지를 하나 만들어주었다
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { userInfoState } from '../recoilAtoms';
import { useRecoilState } from 'recoil';
import axios from 'axios';
export default function KakaoLogin() {
const [userInfo, setUserInfo] = useRecoilState(userInfoState);
const navigate = useNavigate();
const PARAMS = new URL(document.location).searchParams;
const KAKAO_CODE = PARAMS.get('code');
console.log(KAKAO_CODE);
const getAccessToken = async () => {
if (isToken) return; // Return early if fetching
try {
const response = await axios.post(
'http://localhost:4000/auth/kakao/login',
{
authorizationCode: KAKAO_CODE,
},
{
headers: {
'Content-Type': 'application/json',
},
},
);
} catch (error) {
console.error('Error:', error);
setIsToken(false);
}
};
return <div>Loding..</div>;
}
페이지의 코드이고 여기까지 인가코드를 받아오는 과정이다
인가코드는 카카오에서 우리의 url로 전달해주니 확인바란다
http://localhost:3000/auth?code=cxckzfq18ZbHAZK9TjVn8ZE17pCAQYK_NkSf0fWL4Yh94qIsDo4o8sKJuPAKPXLqAAABi6d_8lXE017PSiBv1Q
이런식으로 ..!
url에서 code를 추출하여 서버로 전송하면 클라이언트측의 1차 업무는 끝이난다
서버에선 이제 그 인가코드를 받아 토큰을 발급받을 것이다
서버에서 해주여아 할 것은 일단은..
1. 토큰 발급
2. 발급한 토큰을 이용하여 유저의 정보를 가져온다
업무쪼개기
카카오에서 요구하는 헤더와 바디를 설정해주자
client_secret은 따로 생성해두지 않았다면 스킵
만약 이미 생성했다면 꼭 ! 추가해주자
Content-Type : application/x-www-form-urlencoded (고정)
code : 인가코드
grant_type : authorization_code (고정)
client_id : 위에있는거
redirect_url : 위에있는거
이렇게 토큰이 발급되는 것을 확인할 수 있다
유의할 점은 인가코드가 유효한지 확인해보아야한다
data: {
error: 'invalid_grant',
error_description: 'authorization code not found for code=C048j_fFOKbh6ec4Vn1CjIQylCg1OzH2bOEPaObOVihVcr_hK3Ev9LcvAHgKPXUZAAABi6eS7_kq17LwdM8QAg',
error_code: 'KOE320'
}
이런 에러를 만났다면 인가코드를 다시 발급받은 후에 확인해보자
router.post('/kakao/login', getToken, getUserInfo);
나의 경우 auth를 라우터로 지정해 주었고
클라이언트 측에서 auth/kakao/login으로 요청 시 위에 코드가 실행될 것이다
getToken과 getUserInfo를 미들웨어로 설정해주었다
const getToken = async (req, res, next) => {
const CLIENT_ID = '님의 클라이언트ID';
const REDIRECT_URL = '님의 리다이렉트URL:';
const code = req.body.authorizationCode;
//client 측 참고바람
const kakaoTokenUrl = `https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URL}&code=${code}`;
//QueryString 형식으로 보내주어야 한다
const kakaoHeader = {
'Content-type': 'application/x-www-form-urlencoded;charset=utf-8',
};
await axios
.post(kakaoTokenUrl, {
headers: kakaoHeader,
})
.then((res) => {
console.log('good');
console.log(res.data);
})
.catch((err) => {
console.log('err');
console.log(err);
});
};
해당 에러를 만났을 경우 체크해야할 점을 말해주겠다
1. 위 설명대로 client_secret값을 생성해놓고 추가하지 않은 경우
단순히 body에 추가해주면 될 듯 하다
나의 경우 원래는 client_secret값을 생성도 해 놓았고 body에 추가하였으나 그것이 해결되지 않았다
그리고 생성했던 client_secret값을 삭제하고 다시 해보아도 동일한 에러가 계속 나왔고
이 에러를 마주친 대부분이 1번의 경우는 아닐 것이라는 생각이 든다
2. body데이터를 쿼리스트링으로 변환하여 전달해보자
구글링을 해본 결과 해당 방법으로 해결하신 분의 사례를 보았고 나도 적용해 보았다
const requestData = {
grant_type: 'authorization_code',
client_id: '님의 ID',
redirect_uri: '님의 URL',
code: req.body.authorizationCode,
};
const queryStringBody = Object.keys(requestData)
.map((el) => encodeURIComponent(el) + '=' + encodeURI(requestData[el]))
.join('&');
위 함수를 이용하면 데이터를 쿼리스트링의 형태로 보낼 수 있다
await axios
.post(kakaoTokenUrl, {
headers: kakaoHeader,
}, {
queryStringBody
})
.then((res) => {
console.log('good');
console.log(res.data);
})
.catch((err) => {
console.log('err');
console.log(err);
});
grant_type=authorization_code&client_id=님의ID&redirect_uri=님의URL&code=e7Av1NbGITfwnOMMMTKNTXzQ4hMSPmVTl6kvChVrVcQj_fl_EK1b7OHf9kEKKwymAAABi6eX8VnUNEQ5evY1pg
이런 모양으로 만들어서 전송된다
나는 물론 이것으로도 해결하지 못했다
참고 링크 : https://kdinner.tistory.com/92
3. GET요청을 하듯 URL에 QueryString형태로 데이터를 전송해보자
내가 해결한 방법이다
const kakaoTokenUrl = `https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URL}&code=${code}`;
body 데이터를 담은 url변수를 만든 후에
await axios
.post(kakaoTokenUrl, {
headers: kakaoHeader,
})
.then((res) => {
console.log('good');
console.log(res.data);
})
.catch((err) => {
console.log('err');
console.log(err);
});
};
따로 데이터를 추가하지 않고 url만을 이용하여 post요청을 했다 그 결과 ..
토큰이 웃으며 나를 반겨주었다