카카오 소셜 로그인을 구현했던 과정을 기록
이번 글은 supabase에서 소셜 로그인을 할 수 있는지 모르고ㅜ 토큰을 발급받아 유저 정보를 반환 받는 과정까지만 구현한 내용이다.
supabase의 Auth Providers를 활용한 내용은 다음편에 작성할 예정
https://developers.kakao.com/docs/latest/ko/kakaologin/common
왼쪽의 설정하기 메뉴를 보면 카카오 로그인 활성화 설정, Redirect URI 등록은 필수 사항이라고 안내되어 있다.
어플리케이션을 등록하고 내 어플리케이션 메뉴로 들어가서 설정해준다.


동의 항목 설정

닉네임과 프로필 사진은 그냥 설정할 수 있지만 카카오계정(이메일)은 비즈니스 앱으로 등록되어 있어야 한다. (사업자 번호가 없다면 개인 개발자로 등록하면 됨)

플랫폼 메뉴에 도메인도 함께 등록

로그인이 진행되는 과정을 살펴보면, 카카오 계정으로 로그인을 요청하면 카카오에서 Redirect URI로 인증 코드를 query parameter로 전달한다. 이 코드로 다시 카카오에 토큰을 발급받고, 토큰을 통해서 유저 정보를 가져올 수 있다.
✅ 카카오 로그인 과정은 인증 코드 받기 → 토큰 받기 → 유저 정보 받기 순차적으로 진행

카카오 계정으로 로그인 요청하고, 인증 코드 받기
1-1 login 버튼 만들기
/login/page.tsx
const Login = () => {
// 카카오 REST API 키
const REST_API_KEY = process.env.NEXT_PUBLIC_KAKAO_LOGIN_REST_API_KEY;
// 설정한 REDIRECT_URI
const REDIRECT_URI = process.env.NEXT_PUBLIC_KAKAO_LOGIN_REDIRECT_URI;
// 로그인을 요청할 주소
const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}`;
return (
<Link href={KAKAO_AUTH_URL}>
<Image
src={'/kakao_login_medium_wide.png'}
alt='카카오 로그인 이미지'
width={300}
height={45}
/>
</Link>
);
}
Kakao에서 제공하는 로그인 버튼 디자인을 참고해서 만들도록 하자
https://developers.kakao.com/docs/latest/ko/kakaologin/design-guide
1-2 Redirect URI에서 인증 코드 확인하기
?code=#### 식으로 전달 받는다. (http://localhost:3000/auth/callback/kakao?code=####)useSearchParams를 이용해 query parameter를 받아온다./auth/callback/kakao/page.tsx
const LoginRedirection = () => {
const router = useRouter();
const authCode = useSearchParams().get('code');
console.log(authCode);
return (
<div>
<h2>loading...</h2>
</div>
);
인증 코드를 전달해 토큰 발급 받기
2-1 카카오에 인증 코드를 보내서 토큰 받는 함수 만들기
/api/login.ts
export const getKakaoLoginToken = async (code: string) => {
const tokenUrl = 'https://kauth.kakao.com/oauth/token';
const REST_API_KEY = process.env.NEXT_PUBLIC_KAKAO_LOGIN_REST_API_KEY;
const REDIRECT_URI = process.env.NEXT_PUBLIC_KAKAO_LOGIN_REDIRECT_URI;
const params = new URLSearchParams({
grant_type: 'authorization_code',
client_id: REST_API_KEY!,
redirect_uri: REDIRECT_URI!,
code: code,
});
try {
const response = await fetch(tokenUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
},
body: params,
});
if (!response.ok) {
throw new Error(`${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error(error);
}
};
2-2 Redirect URI 페이지가 렌더링될 때 위에서 만든 토큰 발급 함수를 실행 시키고 로컬 스토리지에 저장하기
/auth/callback/kakao/page.tsx
useEffect(() => {
const fetchLoginToken = async (code: string) => {
if (typeof code === 'string') {
try {
const data = await getKakaoLoginToken(code);
localStorage.setItem('token', JSON.stringify(data));
return data;
} catch (error) {
console.error(error);
}
}
};
const handleLogin = async (code: string) => {
try {
// 토큰 받기
const token = await fetchLoginToken(code);
} catch (error) {
console.error(error);
}
};
if (authCode) {
handleLogin(authCode);
}
}, [authCode, router]);
발급 받은 토큰으로 유저 정보 받기
3-1 카카오에 토큰 보내서 유저 정보 받는 함수 만들기
/api/login.ts
export interface Token {
token_type?: string;
access_token: string;
refresh_token?: string;
id_token?: string;
expires_in?: number;
refresh_token_expires_in?: string;
scope?: string;
token?: string;
id?: number;
}
export const getKakaoUserInfo = async ({ access_token }: Token) => {
const userInfoUrl = 'https://kapi.kakao.com/v2/user/me';
try {
const response = await fetch(userInfoUrl, {
method: 'GET',
headers: {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
},
});
if (!response.ok) {
throw new Error(`${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error(error);
}
};
3-2 Redirect URI 페이지 렌더링 후 토큰 발급 받고 나서 유저 정보를 요청하고 로컬 스토리지에 저장하기
/auth/callback/kakao/page.tsx
useEffect(() => {
const fetchUserInfo = async (token: Token) => {
try {
const data = await getKakaoUserInfo(token);
localStorage.setItem('userInfo', JSON.stringify(data));
return data;
} catch (error) {
console.error(error);
}
};
const handleLogin = async (code: string) => {
try {
// 토큰 받기
const token = await fetchLoginToken(code);
// 유저 정보 받기
if (token) {
await fetchUserInfo(token);
}
} catch (error) {
console.error(error);
}
};
if (authCode) {
handleLogin(authCode);
}
}, [authCode, router]);
위에서 전달 받은 유저 정보로 supabase의 user 테이블에 저장하면 될 듯하다.
다음 편에서는 Next.js의 route와 supabase의 Auth Provider를 이용해서 간단하게 로그인하고 트리거로 public.user 테이블에 데이터를 생성하는 방법을 알아보자.