개발환경 구성을 했으니, 카카오 소셜 로그인을 구현해봅시다!
💡 소셜 로그인 개발환경 구성하기를 읽고 오시면 더 이해가 편하실거예요. :)

Kakao Developer에 로그인을 하고, 앱을 등록해주세요.
등록한 애플리케이션에 들어가면, 앱 키가 있습니다.
여기서 우리는 REST API 키를 사용할거예요.

이 부분을 작성해야 추후 로그인했을 때, 등록해둔 URI로 Kakao쪽에서 redirect를 수행합니다.
프론트엔드로 redirect가 발생할 수 있도록 적어주세요.
그리고 위 이미지 표시처럼 활성화 설정을 꼭 ON 하셔야합니다.

카카오 최초 로그인 시에 사용자 정보를 제공하는 동의 권한을 설정할 수 있습니다.
테스트니 닉네임만 필수 동의로 할게요.😊
Kakao로부터 인가코드를 받아올 URL을 백엔드 서버에서 만들어 클라이언트에게 API로 제공합니다.
그 전에 먼저, 프로젝트 루트에 .env 파일을 생성합니다.
.env파일은 보안과 관련된 값을 관리합니다.
// .env
KAKAO_KEY=[YOUR KAKAO REST API KEY]
kakao.js에 Kakao와 관련된 기능들을 모듈화하는 클래스를 만듭니다.
// src/kakao.js
class Kakao {
constructor() {
this.key = process.env.KAKAO_KEY;
this.redirectUri = `http://localhost:3000/callback/kakao`;
}
/**
* @description 카카오 인가코드를 받기위한 URL 가져오기
*/
getAuthCodeURL() {
return `https://kauth.kakao.com/oauth/authorize?client_id=${this.key}&redirect_uri=${this.redirectUri}&response_type=code`;
}
}
export const KakaoClient = new Kakao();
이제 app.js 파일에 API를 만듭니다.
// src/app.js
...생략
import Kakao from "./kakao.js";
...생략
app.get("/kakao/url", (req, res, next) => {
console.log("/kakao/url start");
const url = KakaoClient.getAuthCodeURL();
res.status(200).json({
url,
});
console.log("/kakao/url finish");
});
...생략
프론트엔드에서는 해당 API를 호출하여, 받은 url로 카카오 로그인 페이지를 보여줄거예요.😊
💡 필자는 Client ID를 프론트엔드에서 관리하지 않고, 백엔드에서만 관리하도록 하기위해 이런 구성으로 진행해요. :)
💡 Kakao developer - 인가코드 받기에서 자세한 설명을 볼 수 있어요. :)
방금 만든 백엔드 API를 프론트엔드에서 호출합니다.
로그인 버튼을 만들고 클릭 시 API를 호출하도록 구현할게요.😊
버튼 컴포넌트인 KakaoButton.js를 만듭니다.
// src/KakaoButton.js
function KakaoButton() {
/**
* @description URL 가져오기
*/
const fetchGetURL = async () => {
try {
const { url } = await (
await fetch("http://localhost:3001/kakao/url")
).json();
console.log(url); // 응답으로 온 url
} catch (error) {
alert("Function fetchGetURL error!");
console.error(error);
}
};
return (
<button className="kakao" onClick={fetchGetURL}>
카카오 로그인하기
</button>
);
}
export default KakaoButton;
App.js에서 KakaoButton 컴포넌트를 렌더합니다.
// src/App.js
import "./App.css";
import KakaoButton from "./KakaoButton";
function App() {
return (
<div className="App">
<KakaoButton /> {/* 버튼 컴포넌트 */}
</div>
);
}
export default App;
App.css에서 버튼 스타일을 추가합니다.
/* src/App.css */
...기존 코드 생략
.kakao {
background-color: #fee500;
color: #000000;
}
.kakao:hover {
background-color: #f4dd0a;
}
.kakao:active {
background-color: #ead514;
}

이제 버튼을 누르면 개발자 도구에 API 응답이 로그로 남습니다!!
응답받은 url로 페이지를 이동시킵니다.
KakaoButton.js의 fetchGetUrl 함수를 조금 수정합니다.
// src/KakaoButton.js
...생략
const fetchGetURL = async () => {
try {
const { url } = await (
await fetch("http://localhost:3001/kakao/url")
).json();
console.log(url);
document.location.href = url; // 👈 이 부분을 추가로 넣어주세요. (페이지 이동)
} catch (error) {
alert("Function fetchGetURL error!");
console.error(error);
}
};
...생략
다시 버튼을 눌러봅시다!

Kakao Developer에서 설정한대로 닉네임을 필수로 카카오 권한 동의를 받는 화면이 나왔어요!😎
전체 동의하고 계속 진행해볼게요.

설정한 redirect_uri의 주소로 query parameter와 함께 전달되었습니다.
query parameter의 code가 Kakao에서 발급해준 인가코드입니다.
이 인가코드를 백엔드에 보내야하기에, 백엔드에 API를 하나 만들겠습니다.
클라이언트(프론트엔드)로부터 인가코드를 받아 Kakao 로그인 처리를 하겠습니다.
일단 Kakao로 부터 인가코드를 통해 token을 발급받아야 합니다.
발급받은 토큰으로 Kakao의 API를 사용할 수 있습니다.



설명이 아주 자세히 되어있군요.🤩
💡 Kakao developer - 토큰 받기에서 자세한 설명을 볼 수 있어요. :)
이대로 구현해보겠습니다!
Kakao.js파일에 token을 받아오는 메소드를 추가합니다.
// src/kakao.js
import axios from "axios";
class Kakao {
...생략
/**
* @description 토큰 발급하기
* @param code 인가코드
*/
async getToken(code) {
const params = {
client_id: this.key,
code,
grant_type: "authorization_code",
redirect_uri: this.redirectUri,
}; // 👈 필수 parameter만 작성
const { data } = await axios.post(
"https://kauth.kakao.com/oauth/token",
params,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
}, // 👈 헤더 설정
}
);
console.log(data);
const tokenData = {
access_token: data.access_token,
refresh_token: data.refresh_token,
};
return tokenData;
}
...생략



받아온 인증 토큰을 헤더에 설정하고 요청하면, 로그인한 사용자의 정보를 받을 수 있는 API입니다.
💡 Kakao developer - 사용자 정보 가져오기에서 자세한 설명을 볼 수 있어요. :)
이것도 구현해보겠습니다!
// src/kakao.js
class Kakao {
...생략
/**
* @description 유저 정보 가져오기
* @param token 액세스 토큰
*/
async getUserData(token) {
const { data } = await axios.get("https://kapi.kakao.com/v2/user/me", {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log(data);
const userData = {
nickname: data.kakao_account.profile.nickname,
};
return userData;
}
}
...생략
작성한 기능을 토대로 app.js에서 API를 만들어줍니다.
클라이언트로부터 인가코드를 받아 token을 발급받고, 해당 token으로 유저 정보를 받아옵니다.
// src/app.js
...생략
app.post("/login", async (req, res, next) => {
console.log("/login start");
try {
const { code } = req.body;
const { access_token } = await KakaoClient.getToken(code); // 토큰 받아오기
const userData = await KakaoClient.getUserData(access_token); // 유저 정보 받아오기
// 그 후 DB로 사용자 등록 처리
// 세션 or 토큰 처리
// 등등 로그인 관련 처리를 해줘야 함
res.status(200).json(userData);
} catch (error) {
console.error(error);
const errorData = {
message: "Internal server error.. :(",
};
res.status(500).json(errorData);
}
console.log("/login finish");
});
...생략
다 완성했습니다!
이제 프론트엔드에서 해당 API를 호출해보도록 할까요?😊
💡 실제 로그인이라면 DB를 조회하고, 해당 서비스의 세션 or 토큰을 발급해주는 등, 다른 작업들도 해야해요. 하지만 이 글에선 그런 내용은 다루지 않아요. :)
로그인 버튼을 누르면 Kakao 로그인 페이지와 동의 화면이 나오고, 미리 설정해둔 redirect_uri 주소로 필요한 인가코드를 전달받았어요.
이제 그 인가코드를 파싱해 아까 작성한 백엔드 API를 호출하겠습니다.
redirect_uri로 설정했던 주소로 라우팅됐을 때 보여질 컴포넌트를 만들어봅시다.
이 컴포넌트에서 url을 읽어, query parameter에서 code를 가져올거예요.
그 후, code값을 body에 실어 API를 호출하겠습니다.
KakaoCallback.js 파일을 만들고 아래처럼 작성합니다.
// src/KakaoCallback.js
import { useCallback, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
function KakaoCallback() {
const [code, setCode] = useState("");
const navigate = useNavigate();
/**
* @description 로그인하기
*/
const fetchLogin = useCallback(
async (code) => {
try {
const param = {
code,
};
const response = await (
await fetch("http://localhost:3001/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(param), // string으로 전달해야함
})
).json();
console.log(response); // { nickname: '#######' }
navigate("/main"); // API 호출 성공 시 메인 페이지로 이동
} catch (error) {
alert("Function fetchLogin error!");
console.error(error);
}
},
[navigate]
);
/**
* @description login API fetch
*/
useEffect(() => {
if (code) {
fetchLogin(code);
}
}, [code, fetchLogin]);
/**
* @description code 값 가져오기
*/
useEffect(() => {
const Address = new URL(window.location.href); // url 가져오기
const code = Address.searchParams.get("code") || ""; // 👈 code value
setCode(code);
}, []);
return <div className="App">Wait....</div>;
}
export default KakaoCallback;
만든 컴포넌트를 라우팅합니다.
// src/index.js
...생략
import KakaoCallback from "./KakaoCallback";
...생략
<Routes>
<Route path="/" element={<App />} />
<Route path="main" element={<Main />} />
<Route path="callback/kakao" element={<KakaoCallback />} /> {/* 👈 이 부분 추가 */}
</Routes>
...생략
이제 다 완성되었습니다!

잘 되는군요! (로그인하는 부분은 지웠고, 동의 받는 화면은 이미 진행을 해서 나오지 않았습니다.)
💡 전체 소스코드는 GitHub에 올려두었어요. :)
Kakao API 호출 시에 에러가 발생한다면, Kakao developer - 문제 해결에서 확인해보세요.
error 내용에 특정 code값이 있을거예요.🙄