REST-API 활용한 카카오 소셜 로그인 구현(feat. React)
프로젝트를 진행하면서 소셜 로그인 구현을 맡게 되었다.
다들 프론트엔드는 소셜 로그인에서 할게 많이 없다 쉽다~, 그중에서 카카오가 가장 쉽다~
이렇게 얘기해서 방심했다.
그렇게 6일간의 소셜 삽질이 시작되었다.
구글링을 해보니 똑같은 카카오 로그인 구현인데도 정말 신기하게 포스팅한 사람들마다 다들 다른 방법을 사용하여 매우 혼란스러웠고 이해하는데 한참 걸렸다.
마침내 성공을 했을 때 극한의 희열감과 이건 반드시 포스팅으로 남겨 놓으리라 다짐하여 지금 글을 작성 중이다.
카카오 개발자 홈페이지를 정말 많이 읽었음에도 프론트엔드가 소셜 로그인을 할 때 어떤 역할을 해주어야 하는지 명확히 감이 오질 않았고 API 활용 방법만 적혀있을 뿐이었다.
프론트와 백엔드의 역할 구분에 대한 개념이 확실히 잡히질 않았기 때문에 처음으로 구현 성공한 사람들의 백엔드 코드도 보고 이것저것 다 보면서 굉장히 깊이 있는 삽질을 하게 되었다.
아래는 REST-API를 활용한 카카오 로그인 문서이다.
developers.kakao.com/docs/latest/ko/kakaologin/rest-api
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com
본문 전 간단 요약
- REST-API를 활용한 카카오 로그인 방법을 사용하였다.
- React - Spring 이 함께 작업하였다.
- 프론트엔드 : 카카오로부터 인가코드를 받고 받은 인가코드를 백엔드에 넘겨주는 역할을 하였다. (+ 마지막 리다이렉팅까지)
- 인가코드를 넘기면 백엔드로부터 우리 사이트 전용 토큰을 발급받았다.
- 백엔드 : 프론트로부터 인가 코드를 넘겨받고 카카오로부터 토큰을 발급받는다. 그리고 해당 토큰에 담긴 유저 정보를 활용해 프로젝트 전용 토큰으로 새롭게 발급 후 프론트에게 돌려준다.
카카오 토큰을 그대로 클라이언트에게 직접 넘겨주고 사용시키면 고소당할 수도 있다고 백엔드 팀원분이 말씀해주심.
생각해보니 해킹당하면 사용자의 카카오 정보 안에 있는 것들이 몽땅 털리는 셈인데 확실히 고소당할 수도 있을듯하다.
대략적인 소셜 로그인의 과정을 그림으로 그려보았다.
백엔드에서는 OAuth, secret Key 설정 등 더 많은 작업이 이루어지지만 정확히 어떤 건지 설명하기엔 전문성이 부족하여
프론트 위주로 작성하였다.
1. 인가 코드 받기
가장 먼저 인가 코드를 받아와야 한다.
developers.kakao.com/docs/latest/ko/kakaologin/rest-api
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com
위에 올린 링크를 타고 들어가면
이렇게 단계별로 설명이 나온다.
조금만 더 내려가면
이런 화면을 볼 수 있는데 처음엔 이게 대체 뭘 뜻하는 걸까... 싶었다.
GET은 메서드인 거 같고 Host는 뭐고 Parameter는 뭐지..?
결론은 URL 구조에 대해 구글링을 좀 하다 보면 대략적으로 이해하게 된다.
URL 구조에 맞게 위 내용을 조합하면
"https://kauth.kakao.com/oauth/authorize?client_id={REST_API_KEY}&redirect_uri={REDIRECT_URI}&response_type=code"
// 파라미터 시작은 ? 로
이렇게 되고 이 주소로 접근을 하면 인가 코드를 받아올 수 있게 된다.
근데 저걸 그대로 쓰면 절대 안 될 거다.
위에 명시됐듯이 cliend_id와 redirect_uri를 받아와서 {REST_API_KEY}와 {REDIRECT_URI}에 채워주어야 한다.
두 가지를 얻으려면 우선 애플리케이션을 생성한다.
cliend_id
cliend_id는 kakao developers에서 내 애플리케이션을 추가했을 때 생기는 REST_API 키를 넣어주면 되고,
Redirect URI
Redirect URI는 카카오 로그인 메뉴에 들어가서 추가를 해준다. 이때 경로 설정은 백엔드와 협의해서 맞춘다.
우린 백엔드분이 하자는 경로로 따라갔다. (oauth/callback/kakao)
대신!! Redirect URI는 반드시 프론트에서 접근할 수 있는 Host로 지정해주어야 한다. (localhost:3000)
왜냐하면 여기에서 인가 코드 받고 넘기고 등등 모든 작업이 이루어져야 하는데 프론트엔드가 접근할 수 없는 Host로 지정을 해버리면 말 그대로 접근을 못하니 아무것도 할 수 없다.
(localhost:8080 등... 대신 이건 백엔드에서 자체 테스트할 때 사용할 수 있음)
(우리는 여기서 정말 많이 헤맸다.)
플랫폼 추가
Web에서 사용할 것이기 때문에 Web 플랫폼에 사이트 도메인을 추가한다.
배포하기 전이기 때문에 localhost:3000으로 설정했다.
배포하면 배포한 주소도 추가해야 함
사실 위 과정은 백엔드든 프론트든 아무나 해도 상관없다.
하지만 반드시 한 사람의 REST_API 혹은 REDIRECT_URI를 따라가야 한다.
(백/프론트 각자 테스트해보겠다고 서로 만들고 나중 가서 URI 꼬이면 작동이 안 된다. 헷갈리기도 하고)
이렇게 모아 온 것들을 한 번에 편하게 관리하기 위해 컴포넌트를 새로 생성하였다.
> OAuth.js
// OAuth.js 라는 컴포넌트를 따로 생성하여 관리하였음
const CLIENT_ID = "11111111111111111111111111111111";
const REDIRECT_URI = "http://localhost:3000/oauth/callback/kakao";
export const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code`;
[카카오 계정 로그인] 버튼을 눌렀을 때 위에서 만든 URL 주소로 연결을 시켜주면 된다.
// Login.js
import { KAKAO_AUTH_URL } from "../shared/OAuth";
<KaKaoBtn href={KAKAO_AUTH_URL}>
<img src={kakaologo}></img>
<span>카카오계정 로그인</span>
</KaKaoBtn>
그러면 버튼을 눌렀을때 카카오톡 로그인 화면으로 이동이 되고, 이메일-비밀번호를 입력하면 아래와 같이 동의하기 화면이 나온다.
여기서! 동의하고 계속하기를 누르면 이동되는 화면이 Redirect_URI 화면이다.
이 화면에서 보이지 않는 모든 것이 이루어진다.
위에 보이는 화면이 카카오가 리다이렉팅 시킨 화면이다.
(앞서 설정한 URI와 캡처본의 URI가 다른데 캡쳐 시기상 달라진 것일 뿐이니 신경 쓰지 말고 진행하면 된다.)
주소창을 보면 Redirect_URI 뒤에 파라미터로 ?code=@@@@@@@@@@@@@
인가 코드가 넘어온 것을 확인할 수 있다.
우리에게 필요한 것이 이 인가 코드이다.
파라미터로 넘어온 인가 코드를 가져와야 하는데 이때 사용하면 좋은 명령어가 있다.
window.location.href
현재 화면의 주소창을 확인할 수 있다. 아무 페이지나 들어가서 개발자 도구 콘솔에 테스트해보길
그리고 이 내용을 그대로 URL에 집어넣어서 보게 되면 해당 주소에 대한 자세한 정보를 볼 수 있다.
new URL( )
잘 보면 search라는 파라미터 안에 인가 코드가 예쁘게 잘 담겨있는 것을 알 수 있다.
구성상 ?code={코드 내용} 이렇게 되는데 그럼 "code"라는 key에 있는 value를 꺼내면 된다.
let 변수명 = new URL(window.location.href).searchParams.get('code')
URL 안에 search 파라미터에 들어있는 'code'라는 값을 get 하겠다.
이렇게 하면 '변수명'이라는 변수 안에 인가 코드 정보가 담기게 된다.
근데 해당 작업을 콘솔에서 할 순 없고 이걸 어떤 컴포넌트에서 작업을 해야 할지가 처음엔 아리송했다.
해답은 우리는 현재 Redirect_URI의 경로를 알고 있으니
(위에선 localhost:3000/oauth/callback/kakao 라고 임의로 지정하였음)
해당 경로에 도달했을 때 보여줄 컴포넌트를 생성하고 App.js에서 Route만 걸어주면 된다.
컴포넌트를 OAuth2RedirectHandler.js 라고 이름을 지었다.
(알아만 볼 수 있게 kakao.js 혹은 social.js 라고 적어도 됨 뭐든 자유)
이 컴포넌트가 리다이렉트 되는 화면으로서 사용될 것이기 때문에 여기에 인가 코드를 받아오는 코드를 적어주었다.
그리고 네트워크가 느린 사용자들은 리다이렉팅 되는 화면을 무방비로 보게 될 것인데 이 화면이 그냥 하얀 화면이면 무슨 상황인지 사용자는 알 턱이 없고 당황할 수도 있기 때문에 spinner를 만들어 넣었다.
인가 코드를 받아오면 axios를 활용해 코드를 백엔드에게 넘겨줄 것이다.
// 리다이렉트될 화면
// OAuth2RedirectHandeler.js
import React from "react";
import { useDispatch } from "react-redux";
import { actionCreators as userActions } from "../redux/modules/user";
import Spinner from "./Spinner";
const OAuth2RedirectHandler = (props) => {
const dispatch = useDispatch();
// 인가코드
let code = new URL(window.location.href).searchParams.get("code");
React.useEffect(async () => {
await dispatch(userActions.kakaoLogin(code));
}, []);
return <Spinner />;
};
export default OAuth2RedirectHandler;
App.js 에서 해당 컴포넌트 경로 설정(Redirect_URI 경로로)
// App.js
function App() {
return (
<React.Fragment>
<ConnectedRouter history={history}>
<Route path="/signup" exact component={Signup} />
<Route path="/login" exact component={Login} />
<Route path="/oauth/callback/kakao" component={OAuth2RedirectHandler}></Route>
</ConnectedRouter>
</React.Fragment>
);
}
2. 인가 코드 백엔드에 넘기고 토큰 받기
// redux > modules > user.js
const kakaoLogin = (code) => {
return function (dispatch, getState, { history }) {
axios({
method: "GET",
url: `http://3.35.208.142/oauth/callback/kakao?code=${code}`,
})
.then((res) => {
console.log(res); // 토큰이 넘어올 것임
const ACCESS_TOKEN = res.data.accessToken;
localStorage.setItem("token", ACCESS_TOKEN); //예시로 로컬에 저장함
history.replace("/main") // 토큰 받았았고 로그인됐으니 화면 전환시켜줌(메인으로)
}.catch((err) => {
console.log("소셜로그인 에러", err);
window.alert("로그인에 실패하였습니다.");
history.replace("/login"); // 로그인 실패하면 로그인화면으로 돌려보냄
}
}
};
소셜 로그인을 거의 다 성공했는데 막혀서 정말 많은 시간을 쏟았던 부분이다.
(401, 403, 500 등 정말 많은 종류의 에러를 만남)
처음엔 인가 코드를 data에 담아서 POST 메서드로 백엔드에 넘기려고 했었다.
그렇게 하니 신기하게 코드가 넘어가긴 하는데 500 error가 발생하고 백엔드 측으로부터 토큰을 넘겨받지 못하였다.
그래서 방법을 바꾸고 검색을 계속하다가 Redirect_URI는 프론트와 백엔드 모두 일치해야 한다는 누군가의 답변 때문에
설마 통신을 할 때 적는 url 에도 Redirect_URI를 적어야 하나 싶어서 localhost:3000/oauth/callback/kakao 를 넣고 통신을 시도했다. 정말 바보 같은 짓이었다. 내 핸드폰으로 내 전화번호에 전화 거는 셈;;
통신이 될 리가 없었다.
(그만큼 애간장이 탔다.)
그러다 마지막으로 인가 코드는 쿼리 스트링으로 넘겨야 한다 인식한다는 어느 카카오 관계자의 답변을 보게 되어...
(출처는 기억나지 않는다.)
data 형식 다 빼고 url 뒤에 파라미터로 담아서 넘기면서 메서드는 GET을 썼다.
`http://{서버주소}?code=${code}`
그렇게 로그인에 성공했다.
토큰을 받아오고 저장을 하였으니(예시로 로컬) 사용자를
계속 Spinner가 돌고 있는 화면으로부터(Oauth2RedirectHandler.js)
다른 곳으로 이동시켜야 했다.
그래서. then() 안에 history.replace("/main") 으로 메인화면으로 보내줌으로써 소셜 로그인이 마무리되었다.
하고 보니 프론트엔드는 과정이 생각보다 단순했다.
결론은
알고 봤을 때는 쉽긴 한데... 아무것도 모르는 상태에서 내가 뭘 해야 할지도 모른 채 처음부터 하려니 정말 쉽지 않았다.
더 많은 것들을 도전해보면서 계속해서 경험치를 많이 쌓아보는 것이 답인 것 같다.
아래는 Redirect_URI가 왜 같아야 하는지 알기 위해 백엔드 팀원분이 참고한 블로그들 중 하나이다.
Kakao Rest API "Redirect URI mismatch." 에러 처리하기
나의 이슈 Spring boot에서 Kakao REST API를 사용해야했는데, 'Kakao REST API > 사용자 관리 > 로그인 > 사용자 토큰 받기' 에서 문제가 발생했다. 사용자 토큰 받기 API 설명을 보면 아래와 같다. 위에 설명
gogomalibu.tistory.com