사이드 프로젝트에 일반 로그인을 구현한 후, 소셜 로그인(Kakao 로그인)을 추가 하려고 했고 Kakao 로그인을 직접 구현하여 Next.js와 next/auth를 사용한 구현 간의 차이를 비교하고자 했습니다.
큰 과정은 위 사진을 참고하며 구현하였고 프론트에서 처리할지, 백에서 처리할지 나뉘는데 나는 프론트(next)에서 처리를 하였고 우리 서비스 회원 여부확인만 백엔드로 위임하였다.
사용자가 카카오 로그인 버튼을 누른다.
프론트엔드에서는 카카오 인가 서버에 로그인 페이지를 요청한다.
이때, redirectUri를 정의하여 카카오 디벨로퍼에도 등록한다!
const handleSignWithKaKao = () => {
const kakao = kakaoInit();
// 카카오 인가 서버로 인가 코드 요청
kakao.Auth.authorize({
redirectUri: `${process.env.NEXT_PUBLIC_APP_HOST_NAME}/callback/kakao/authorize`,
});
};
사용자는 아이디, 비밀번호 및 동의 항목을 카카오 인가 서버로 전달한다.
카카오 인가 서버는 인가 코드를 발급하고 이전에 정의한 redirectUri로 리다이렉트한다.
인가 코드를 받은 후, 프론트 엔드에서 이 인가 코드를 카카오 인가 서버로 전송해야 하고 이 코드는 접근 토큰을 받기 위한 과정이다.
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 } };
};
카카오 인가 서버는 인가 코드를 확인하고 접근 토큰을 반환합니다. 이 과정은 이미 작성한 코드와 동일하다.
프론트 엔드는 받은 접근 토큰을 리소스 서버로 전송한다.
이 토큰은 리소스 서버에서 사용자 정보를 가져오기 위한 권한을 부여해준다.
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와 같은 추가 정보를 입력받지 않아 문제가 발생하고 있어서 현재는 백엔드에서 임의의 데이터를 생성하고 사용자가 나중에 수정할 수 있는 방식으로 문제를 해결했다.
추후에는 아래와 같은 방법으로 문제를 해결하고자 한다.
- 카카오 로그인 후 추가 정보 입력 페이지 이동
- 카카오 로그인 정보와 추가 정보 통합
- 회원가입 완료