728x90
반응형
카카오 소셜 로그인을 구현하기 위해서 먼저 kakao developers에서 설정을 해주어야 한다.
먼저, 내 애플리케이션 > 애플리케이션 추가하기를 클릭하고, 앱 이름과 사업자 정보를 입력하여 애플리케이션 생성한다.
생성된 애플리케이션에 들어가서, 앱 설정 > 플랫폼에서 웹 플랫폼을 추가한다.
다음으로, 앱 설정 > 카카오 로그인에 들어가서 활성화 설정을 ON으로 하고, http://localhost:3000/api/auth/callback/kakao를 Redirect URI로 추가한다. ( 프로덕션 환경에서는 프로덕션 URL을 사용 )
.env 파일을 만들어준다. .env 파일에는 앞에서 추가한 REDIRECT URI와 REST API KEY를 설정해주어야 한다. REST API KEY는 앱 설정 > 앱 키에서 확인할 수 있다.
KAKAO_REST_API_KEY={본인의 키 확인해서 복붙!}
KAKAO_REDIRECT_URI=http://localhost:3000/api/auth/kakao/callback
이제 코드를 작성할건데, 폴더 구조는 다음과 같다.
src/
├── app/
│ ├── layout.tsx # RootLayout
│ ├── page.tsx # 로그인 버튼 포함 메인 페이지
│ ├── mybag/
│ │ └── page.tsx # 사용자 정보를 보여주는 페이지
├── pages/
│ └── api/
│ └── auth/
│ ├── kakao/
│ │ ├── login.ts # 카카오 인증 요청
│ │ └── callback.ts # 카카오 인증 후 처리
참고로, App Router(app/ 폴더)는 API Routes를 지원하지 않기 때문에 API 라우트는 반드시 src/pages/api 아래에 위치해야 한다. src/api 아래에 있으면 라우팅이 제대로 동작하지 않는다.
사용자가 "카카오로 시작하기" 버튼을 누르면 카카오 로그인 페이지로 리다이렉트된다.
// page.tsx
const handleKakaoLogin = () => {
window.location.href = "/api/auth/kakao/login"; // 서버에서 카카오 인증 URL 생성
};
...
<button
onClick={handleKakaoLogin}
className="font-nanum bg-[#F9E000] text-[#333B58] py-3 rounded-md w-full text-center flex flex-row items-center justify-center gap-3 absolute bottom-5 left-0 right-0 mx-auto max-w-[calc(100%-2rem)] text-[16px] font-bold"
>
<IoChatbubbleSharp />
카카오로 시작하기
</button>
카카오로 인증 요청을 보내기 위해 서버에서 OAuth 인증 URL을 생성한다.
// login.ts
const kakaoAuthURL = `https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${KAKAO_REST_API_KEY}&redirect_uri=${KAKAO_REDIRECT_URI}`;
res.redirect(kakaoAuthURL);
사용자가 카카오 로그인 페이지에서 인증을 완료하면, 카카오는 Redirect URI로 인증 코드를 전달한다.
아래 코드에서 code에 인증 코드가 저장되고, 이 코드는 Access Token을 요청하는 데 사용된다.
// callback.ts
export default async function handler(req: NextApiRequest, res: NextApiResponse): Promise<void> {
const { code } = req.query;
if (!code) {
res.status(400).json({ error: 'Authorization code not found' });
return;
}
try {
const tokenResponse = await axios.post<TokenResponse>(
'https://kauth.kakao.com/oauth/token',
new URLSearchParams({
grant_type: 'authorization_code',
client_id: process.env.KAKAO_REST_API_KEY || '',
redirect_uri: process.env.KAKAO_REDIRECT_URI || '',
code: code as string,
}),
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
);
const { access_token } = tokenResponse.data;
const userResponse = await axios.get<KakaoUser>('https://kapi.kakao.com/v2/user/me', {
headers: {
Authorization: `Bearer ${access_token}`,
},
});
const userData = userResponse.data;
res.redirect(`/mybag?user=${encodeURIComponent(JSON.stringify(userData))}`);
} catch (error) {
console.error(error);
res.status(500).json({ error: 'Failed to fetch access token or user info' });
}
}
728x90
반응형