Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
Tags
- 최원영 저자
- 자격증
- boj
- 이해할 수 있는
- 엘리스코딩
- 자바스크립트
- 노마드 코더
- 노마드코더
- Do it! 시리즈
- 백준
- IT 지식
- 노개북
- 알고리즘
- nomadcoders
- 모던 자바스크립트 deep dive
- 제로베이스
- SQLD
- javascript
- K-Digital Credit
- 공부를 가장한 일기일지도
- SQL 개발자
- 톺아보기
- CodeStates
- 오블완
- js
- 비전공자를 위한
- 프로그래머스
- 개발자북클럽
- 구름edu
- 티스토리챌린지
Archives
- Today
- Total
개발자를 희망하는 초보의 자기개발 이야기
[카카오 로그인] 리액트로 카카오 로그인 구현하기 - 프론트엔드 (2) 본문
반응형
카카오 로그인 구현하기 - 프론트엔드 (2)
이전 글에서는 카카오 로그인 버튼을 만들고 로그인 페이지로 이동하는 과정을 다루었다. 이번 글에서는 인가 코드 처리 및 백엔드 연동을 이어서 다룬다.
1. 인가 코드 가져오기 (useSearchParams)
카카오 로그인 후 사용자는 인가 코드(authorization code) 를 Query String으로 받게 된다.
http://localhost:3000/callback?code=nuAFZmJvzl2a5Oz5acQckm8RzTmfSTea9y1SiczkbKjZNN9XyVDNeQAAAAQKPCPnAAABlXhW9uSi-KZYUq23DA
이제 이 인가 코드(nuAFZmJ...)를 백엔드에 전달하여 JWT 토큰을 받아야 한다.
import { useSearchParams } from "next/navigation";
const searchParams = useSearchParams();
const code = searchParams.get("code");
console.log("카카오 인가 코드:", code);
- 변수 code에 인가코드를 담았다.
2. Axios 설정
백엔드와 API 요청을 할 수 있도록 axios를 설정한다.
import axios from "axios";
const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
headers: {
"Content-Type": "application/json",
},
});
api.interceptors.request.use(
(config) => {
const accessToken = useAuthStore.getState().accessToken;
if (accessToken) {
config.headers.access = accessToken;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
export default api;
3. 인가 코드 백엔드로 보내기
인가 코드를 백엔드로 보내서 JWT 토큰을 받아오는 API 요청 함수를 작성한다.
// src/services/authService.ts
import api from "@/lib/axiosInstance";
import { useAuthStore } from "@/store/authStore";
export const kakaoLogin = async (code: string) => {
try {
const response = await api.get(`/auth/kakao?code=${code}`);
const accessToken = response.headers["access"];
useAuthStore.getState().setAuth(accessToken);
return response.data;
} catch (error) {
console.error("카카오 로그인 실패:", error);
throw error;
}
};
- JWT 토큰을 Zustand를 이용해 저장할 예정이다.
- 우리팀은 토큰을 받을 때 헤더에 'access' 라는 키로 받기로 했었다.
- 여러 블로그에서 Authorization로 토큰값을 처리하던데 이건 고정키가 아니니 response.headers로 먼저 확인해볼 것.
4. Zustand로 로그인 상태 관리
Zustand를 이용하여 로그인 상태를 저장한다.
// src/store/authStore.ts
"use client";
import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";
interface AuthState {
accessToken: string | null;
setAuth: (accessToken: string) => void;
logout: () => void;
}
export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
accessToken: null,
setAuth: (accessToken) => set({ accessToken }),
logout: () => set({ accessToken: null }),
}),
{
name: "token",
storage: createJSONStorage(() => sessionStorage),
}
)
);
- Zustand의 persist 미들웨어를 사용하면 상태에 따라 세션 스토리지에 자동 저장된다.
5. Callback 페이지 구현 (KakaoCallback.tsx)
"use client";
import { useEffect } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { kakaoLogin } from "@/services/authService";
const KakaoCallback = () => {
const router = useRouter();
const searchParams = useSearchParams();
const code = searchParams.get("code");
useEffect(() => {
if (!code) {
console.error("카카오 로그인 실패: code 값 없음");
router.push("/main");
return;
}
const handleKakaoLogin = async () => {
try {
await kakaoLogin(code);
router.push("/home");
} catch (error) {
console.error("카카오 로그인 요청 실패:", error);
router.push("/main");
}
};
handleKakaoLogin();
}, [code, router]);
return <div>로그인 처리 중...</div>;
};
export default KakaoCallback;
- 로그인 성공 시 /home으로 이동, 실패 시 /main으로 돌아간다.
6. axios 인터셉터 설정
// src/lib/axiosInstance.ts
import axios from "axios";
import { useAuthStore } from "@/store/authStore";
const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
headers: {
"Content-Type": "application/json",
},
withCredentials: true,
});
api.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
await api.post("/auth/refresh-token");
return api(originalRequest);
} catch (refreshError) {
console.error("토큰 갱신 실패, 로그아웃 필요:", refreshError);
useAuthStore.getState().logout();
window.location.href = "/main";
}
}
return Promise.reject(error);
}
);
export default api;
- 인터셉터를 통해 JWT 토큰이 만료되면 자동으로 갱신 요청을 한다.
7. 로그인 상태에 따른 UI 변경
"use client";
import { useAuthStore } from "@/store/authStore";
import KakaoLoginButton from "@/components/KakaoLoginButton";
export default function MainPage() {
const accessToken = useAuthStore((state) => state.accessToken);
return (
<div className="w-full flex justify-center items-center">
{accessToken ? <p>환영합니다!</p> : <KakaoLoginButton />}
</div>
);
}
- 로그인 여부에 따라 UI를 변경할 수 있다.
하지만 위의 방법은 세션 스토리지를 통해서 토큰을 관리하기 때문에 보안에 취약하다.
이어서 다음 글에서 withCredentials 설정과 HttpOnly 쿠키를 이용한 로그인 유지 방식을 진행한다.
2025.03.18 - [프론트엔드(Front-end)] - [카카오 로그인] 리액트로 카카오 로그인 구현하기 - 프론트엔드 (3)
참고자료
- https://velog.io/@pakxe/React-%EC%A0%95%EB%A7%90-%EC%89%BD%EB%8B%A4-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%90%EC%84%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B3%A0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0
- https://velog.io/@wynter24/%ED%94%84%EB%A1%A0%ED%8A%B8%EA%B0%80-%ED%95%98%EB%8A%94-%EC%B9%B4%EC%B9%B4%EC%98%A4-%EC%86%8C%EC%85%9C%EB%A1%9C%EA%B7%B8%EC%9D%B8-React
반응형
'프론트엔드(Front-end)' 카테고리의 다른 글
[카카오 로그인] 리액트로 카카오 로그인 구현하기 - 프론트엔드 (3) (0) | 2025.03.18 |
---|---|
[카카오 로그인] 리액트로 카카오 로그인 구현하기 - 프론트엔드 (1) (0) | 2025.03.06 |
[카카오 로그인] Kakao Developers 설정 (1) | 2025.03.05 |
코딩 질문 잘하는 방법 (0) | 2024.08.22 |
자주 사용하는 마크다운 문법 12가지 (0) | 2024.08.05 |