Google OAuth 로그인 구현하기

오병훈·2025년 4월 20일
0

팀 프로젝트 중 백엔드 구현 이전 단계에서, Google OAuth 로그인을 프론트에서 먼저 구현해두었습니다.
기존에 구현했던 Kakao OAuth 로그인 구조를 확장하는 형태로 Google 로그인을 자연스럽게 통합했습니다.

✅ 이 글은 프론트엔드 단에서 미리 작업해둔 Google OAuth 구현 과정, 코드 설계, 에러 해결 기록 등을 정리한 것입니다.


🛠️ 사전 배경

  • 프로젝트 구조: Next.js (App Router), Zustand, TanStack Query, TailwindCSS

  • 상태 관리: useAuthStore로 로그인 상태 유지

  • 요청 관리: loginWithOauthCode() 함수를 통한 OAuth 로그인 요청

  • OAuth 구현 방식: Web Server Applications 방식 (response_type=code)


✨ Google OAuth 확장 방향

  • 공통된 구조(provider, code)를 유지하면서 Google도 같은 구조로 통합

  • 버튼 UI는 Google의 공식 Material 가이드를 참고

  • SVG 아이콘은 컴포넌트화하여 재사용 가능하도록 개선


1. Google OAuth URL 생성 함수

// api/oauth/google.ts
const GOOGLE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!;
const REDIRECT_URI = `${process.env.NEXT_PUBLIC_REDIRECT_URI}/auth/google/callback`;

const SCOPE = "openid email profile";

export const getGoogleAuthURL = () => {
  const baseUrl = "https://accounts.google.com/o/oauth2/v2/auth";

  const config: Record<string, string> = {
    client_id: GOOGLE_CLIENT_ID,
    redirect_uri: REDIRECT_URI,
    response_type: "code",
    scope: SCOPE,
    access_type: "offline",
    prompt: "consent",
  };

  return `${baseUrl}?${new URLSearchParams(config).toString()}`;
};

📘 설명:

  • Google OAuth 로그인 창으로 리디렉션할 URL을 생성

  • scope는 openid email profile로 기본적인 사용자 정보를 요청

  • Web Server Application 방식이므로 code를 받아 백엔드에서 토큰 교환 필요


2. 공통 로그인 요청 API (loginWithOauthCode의 provider 확장)

// api/oauth/loginWithOauthCode.ts
export const loginWithOauthCode = async (
  provider: "kakao" | "google",
  code: string
) => {
  const url = `/auth/${provider}`;
  const payload = { code };
  return await requestHandler("post", url, payload);
};

📘 설명:

  • Kakao, Google 등 provider 이름과 code만 전달받아 백엔드로 POST 요청

  • 이후 백엔드에서 access_token, id_token 등을 받아 처리할 예정

기존 "kakao" 만 받던 부분을 "kakao" | "google" 로 확장했습니다.


3. 공통 로그인 상태 저장 훅 useOauthLogin

export const useOauthLogin = () => {
  const { login } = useAuthStore();

  return useMutation({
    mutationFn: ({ provider, code }: { provider: "kakao" | "google"; code: string }) =>
      loginWithOauthCode(provider, code),
    onSuccess: () => {
      login();
      // TODO: 추후 user 정보, accessToken 저장 등 확장
    },
  });
};

📘 설명:

  • react-queryuseMutation을 활용해 로그인 요청을 전송

  • 로그인 성공 시 zustand를 사용해 로그인 상태를 true로 변경


4.로그인 페이지 구현

import GoogleLogo from "@/assets/icons/google.svg";

export default function LoginPage() {
  return (
    <div className="flex flex-col items-center justify-center h-screen gap-4">
      <button onClick={handleKakaoLogin}>
        <Image src={kakao} alt="카카오 로그인" />
      </button>

      <button onClick={handleGoogleLogin} className="...">
        <GoogleLogo className="w-5 h-5 mr-3" />
        Google 계정으로 로그인
      </button>
    </div>
  );
}

📘 설명:

  • Kakao 로그인은 이미지 버튼 형태로, Google은 SVG + 텍스트로 구현

  • Google 로고는 SVG 파일을 @svgr/webpack 설정으로 컴포넌트화하여 import


5. 🧩 SVG 적용 방식 개선

Google 로고를 JSX에 직접 작성하지 않고, 컴포넌트 형태로 import하기 위해 @svgr/webpack 설정을 추가했습니다.

npm install --save-dev webpack @svgr/webpack
// next.config.ts
import type { Configuration } from "webpack";

const nextConfig = {
  webpack(config: Configuration) {
    config.module?.rules?.push({
      test: /\.svg$/,
      issuer: /\.(js|ts)x?$/,
      use: ["@svgr/webpack"],
    });
    return config;
  },
};

export default nextConfig;

6. ✅ 최종 구조 정리

파일설명
api/oauth/google.tsGoogle OAuth 인증 URL 생성
api/oauth/loginWithOauthCode.ts공통 로그인 요청 처리 (Kakao/Google)
hooks/useOauthLogin.ts로그인 mutation 처리
components/icons/google.svgGoogle 로고 컴포넌트
app/login/page.tsx로그인 페이지 UI

🔗 참고 자료

profile
Front-End Developer

0개의 댓글