사이드 프로젝트에 일반 로그인을 먼저 구현한 후, 소셜 로그인(카카오 로그인)을 추가하게 되었다. 이 과정에서 카카오 로그인 직접 구현 방식과 Next.js + next-auth를 이용한 방식의 차이를 비교해보기 위해 직접 구현 방식을 선택하였다.

카카오 로그인은 프론트엔드와 백엔드 중 어디서 처리하느냐에 따라 구분되는데, 나는 프론트엔드(Next.js) 에서 대부분의 과정을 처리하고, 회원 여부 확인만 백엔드로 위임하는 구조로 구현했다.
사용자가 카카오 로그인 버튼을 클릭
const handleSignWithKaKao = () => {
const kakao = kakaoInit();
kakao.Auth.authorize({
redirectUri: `${process.env.NEXT_PUBLIC_APP_HOST_NAME}/callback/kakao/authorize`,
});
};
프론트에서 카카오 인가 서버로 로그인 요청을 보낸다. 이때, 리다이렉트 URI는 카카오 디벨로퍼스 콘솔에도 등록되어 있어야 한다.
const handleSignWithKaKao = () => {
const kakao = kakaoInit();
// 카카오 인가 서버로 인가 코드 요청
kakao.Auth.authorize({
redirectUri: `${process.env.NEXT_PUBLIC_APP_HOST_NAME}/callback/kakao/authorize`,
});
};
사용자가 카카오 로그인 화면에서 아이디/비밀번호 입력 및 동의 항목을 체크한다.
카카오 인가 서버는 인가 코드를 발급하고, 사전에 등록한 redirectUri로 리다이렉트한다.
리다이렉트된 프론트에서는 URL에서 인가 코드를 추출하고, 이를 사용해 카카오 인가 서버에 Access Token을 요청한다.
async function fetchAccessToken(code: string): Promise<string> {
const config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
};
const data = new URLSearchParams();
data.append("grant_type", "authorization_code"); // authorization_code로 고정
data.append("client_id", KAKAO_APP_KEY); // 앱 REST API 키
data.append("redirect_uri", `${process.env.NEXT_PUBLIC_APP_HOST_NAME}/callback/kakao/authorize`); // 인가 코드를 전달받을 서비스 서버의 URI
data.append("code", code); // code로 고정
try {
const response = await axios.post("https://kauth.kakao.com/oauth/token", data, config);
return response.data.access_token || "";
} catch (error) {
console.error("Failed to fetch access token:", error);
return "";
}
}
export const getServerSideProps: GetServerSideProps<AuthorizeProps> = async (context) => {
const code = Array.isArray(context.query.code) ? context.query.code[0] : context.query.code || "";
const accessToken = await fetchAccessToken(code);
const res = await fetchUserFromKakao(accessToken);
return { props: { userInfo: res.data } };
};
카카오 인가 서버는 인가 코드가 유효하면 Access Token을 반환한다.
발급받은 Access Token을 사용해 사용자 정보를 요청한다.
export const getServerSideProps: GetServerSideProps<AuthorizeProps> = async (context) => {
const code = Array.isArray(context.query.code) ? context.query.code[0] : context.query.code || "";
// 인가 코드를 사용하여 접근 토큰을 가져옴
const accessToken = await fetchAccessToken(code);
// 접근 토큰을 사용하여 사용자 정보를 가져옴
const res = await fetchUserFromKakao(accessToken);
return { props: { userInfo: res.data } };
};
카카오 리소스 서버는 사용자 정보를 프론트엔드에 응답한다.
받은 사용자 정보를 기반으로, 백엔드에 사용자 존재 여부를 확인 요청한다. 이미 가입된 사용자라면 로그인 처리하고, 아니라면 회원가입 후 로그인 처리한다.
const Authorize = ({ userInfo }: AuthorizeProps) => {
useEffect(() => {
signInOrSignUpKakao();
}, []);
const signInOrSignUpKakao = async () => {
const res = await authApi.kakaoLogin(userInfo.id);
if (res.message === "OK") {
window.location.assign(`${process.env.NEXT_PUBLIC_APP_HOST_NAME}/explore`);
}
};
return <h2>로그인 중입니다..</h2>;
};
현재, 카카오 로그인을 통해 회원가입하는 경우 닉네임, 관심사, MBTI 등의 추가 정보 입력 과정이 누락되어 있는 문제가 있다. 백엔드에서 임의의 기본값을 넣고, 사용자가 나중에 수정할 수 있도록 처리하고 있다.
향후 계획
카카오 로그인 후, 추가 정보 입력 페이지로 이동
입력된 추가 정보와 카카오 로그인 정보를 통합
통합된 정보를 기반으로 회원가입 처리