카카오 로그인 구현 (REST API 방식)
useKakaoLogin hook을 생성
//useKakaoLogin.ts
import axios from "axios";
import axiosInstance from "../api/axiosInstance";
import { useLogin } from "./useLogin";
export const useKakaoLogin = () => {
const { mutate } = useLogin();
const state = "kakao"; //OAuth서버로 부터 전달 받을 state 값을 설정
const CLIENT_ID = import.meta.env.VITE_KAKAO_REST_API_KEY; //vite 사용 시 .env 파일의 환경변수는 import.meta.env.변수명 형태로 가져옵니다.
const REDIRECT_URI = import.meta.env.VITE_KAKAO_REDIRECT_URL;
const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&state=${state}`;
const queryParams = new URLSearchParams(window.location.search);
const code = queryParams.get("code"); //Redirect URI 쿼리 파라미터의 code 값을 가져옵니다.
const kakaoLogin = async () => {
const response = await axios({
method: "post",
url: "https://kauth.kakao.com/oauth/token",
data: {
grant_type: "authorization_code",
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
code,
},
headers: {
"Content-type": " application/x-www-form-urlencoded;charset=utf-8",
},
});
if (response.data.access_token) {
//verify account
(async () => {
const res = await axiosInstance.post(
"verify account api",
{
token: response.data.access_token,
}
);
const { result, email } = res.data.data;
if (result) {
if (result === "VERIFIED") {
/* VERIFIED: 검증 성공하였으나 등록되지 않은 회원 */
// 회원가입 페이지로 이동
} else if (result === "SUCCESS") {
/* SUCCESS:이미 가입된 회원 */
//login
mutate({
email,
snsPlatform: "kakao",
});
} else {
/* INVALID: 토큰 유효하지 않음 */
console.log("Error: 토큰정보가 유효하지 않습니다.");
}
}
})();
}
};
return { kakaoLogin, KAKAO_AUTH_URL };
};
KakaoLoginButton 컴포넌트
//kakaoLoginButton.tsx
import { useEffect } from "react";
import KakaoLogo from "../../assets/icons/kakaoLogo.svg";
import { useKakaoLogin } from "../../lib/hooks/useKakaoLogin";
function KakaoLoginButton() {
//useKakaoLogin hook 사용
const { kakaoLogin, KAKAO_AUTH_URL } = useKakaoLogin();
useEffect(() => {
const queryParams = new URLSearchParams(window.location.search);
const code = queryParams.get("code");
const state = queryParams.get("state");
//구글, 카카오 로그인 모두 REDIRECT_URI/?code=123123123 로 리다이렉트처리되므로 state 값 설정을 통해 플랫폼의 종류를 구분할 수 있습니다.
//state 설정 시 ==> REDIRECT_URI/?code=123123123&state=kakao
if (code && state === "kakao") {
kakaoLogin();
}
}, []);
return (
<button
onClick={() => (window.location.href = KAKAO_AUTH_URL)}
>
<img src={KakaoLogo} alt="Kakao 로그인 로고" />
카카오톡으로 로그인하기
</button>
);
}
export default KakaoLoginButton;
구글로그인도 동일한 방식입니다.
useGoogleLogin hook 생성
//useGoogleLogin.ts
import axios from "axios";
import { useLogin } from "./useLogin";
import axiosInstance from "../api/axiosInstance";
export const useGoogleLogin = () => {
const { mutate } = useLogin();
const state = "google";
const CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID;
const CLIENT_SECRET = import.meta.env.VITE_GOOGLE_CLIENT_SECRET;
const REDIRECT_URI = import.meta.env.VITE_GOOGLE_REDIRECT_URL;
const GOOGLE_AUTH_URL = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=profile%20email&state=${state}`;
const queryParams = new URLSearchParams(window.location.search);
const code = queryParams.get("code");
const googleLogin = async () => {
const response = await axios("https://oauth2.googleapis.com/token", {
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
data: {
code,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
grant_type: "authorization_code",
},
});
if (response.data.access_token) {
//verify account
(async () => {
const res = await axiosInstance.post(
"veriry accout api",
{
token: response.data.id_token,
}
);
const { result, email } = res.data.data;
if (result) {
if (result === "VERIFIED") {
/* VERIFIED: 검증 성공하였으나 등록되지 않은 회원 */
//회원가입 페이지 이동
} else if (result === "SUCCESS") {
/* SUCCESS:이미 가입된 회원 */
//login
mutate({
email,
snsPlatform: "google",
});
} else {
/* INVALID: 토큰 유효하지 않음 */
console.log("Error: 토큰정보가 유효하지 않습니다.");
}
}
})();
}
};
return { googleLogin, GOOGLE_AUTH_URL };
};
GoogleLoginButton 컴포넌트
//GoogleLoginButton.tsx
import { useEffect } from "react";
import GoogleLogo from "../../assets/icons/googleLogo.svg";
import { useGoogleLogin } from "../../lib/hooks/useGoogleLogin";
function GoogleLoginButton() {
const { googleLogin, GOOGLE_AUTH_URL } = useGoogleLogin();
useEffect(() => {
const queryParams = new URLSearchParams(window.location.search);
const code = queryParams.get("code");
const state = queryParams.get("state"); // OAuth2 서버가 전달한 state 파라미터
if (code && state === "google") {
googleLogin();
}
}, []);
return (
<button
onClick={() => (window.location.href = GOOGLE_AUTH_URL)}
>
<img src={GoogleLogo} alt="Google 로고" />
구글로 로그인하기
</button>
);
}
export default GoogleLoginButton;