Projects/Auto Post : SNS 자동 업로더

[AutoPost] Firebase Authentication으로 Google 로그인 구현하기 (with TypeScript + React)

따`ddah 2025. 4. 16. 20:50

 

웹 서비스에서 간편한 로그인 기능은 사용자의 이탈을 줄이는 데 중요한 요소이다.

Firebase Authentication을 활용해 Google 로그인 기능을 웹 앱에 연동하는 방법을 소개한다.


🔧 1. Firebase 프로젝트 생성 및 설정

✅ Firebase 프로젝트 만들기

  1. Firebase Console 에 접속합니다.
  2. 새 프로젝트를 생성합니다.
  3. Firebase Authentication 탭으로 이동해, 로그인 방법에서 Google 로그인을 활성화합니다.

✅ 웹 앱 등록

  1. Firebase Console의 설정(톱니바퀴) > 프로젝트 설정 > 앱 등록 > web
  2. 웹 앱을 등록하고 Firebase SDK 설정 객체를 복사해둡니다.


📦 2. Firebase SDK 초기화 (firebase.ts)

src/pages/firebase.ts 파일에 Firebase 앱을 초기화합니다.

 


⚙️ 3. Vite + React 프로젝트에서 환경변수 설정

.gitignore 파일에 ".env" 추가한 후

.env

.env 파일에 키 값을 넣는다. 

# .env

# GOOGLE FIREBASE
VITE_FIREBASE_API_KEY = "..."
VITE_FIREBASE_AUTH_DOMAIN = "..."
VITE_FIREBASE_DATABASE_URL = "..."
VITE_FIREBASE_PROJECT_ID = "..."
VITE_FIREBASE_STORAGE_BUCKET = "..."
VITE_FIREBASE_MESSAGING_SENDER_ID = "..."
VITE_FIREBASE_APP_ID = "..."
VITE_FIREVASE_MEASUREMENT_ID = "..."

🧩 4. Firebase SDK 초기화

/* client/src/pages/Firebase.tsx */

import { initializeApp } from "firebase/app";
import { getAuth, GoogleAuthProvider } from "firebase/auth";

const firebaseConfig = {
  apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
  authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
  databaseURL: import.meta.env.VITE_FIREBASE_DATABASE_URL,
  projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
  storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
  appId: import.meta.env.VITE_FIREBASE_APP_ID,
  measurementId: import.meta.env.VITE_FIREVASE_MEASUREMENT_ID,
};

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const provider = new GoogleAuthProvider();

export { auth, provider };

✅ 5. 로그인 상태 관리 + 리다이렉트 + 라우팅 유지

 핵심 포인트

  • App() 컴포넌트 안에서 user 상태를 관리해야 한다. 
  • 인증 상태 감지해서 세션에 저장해야 한다. 
  • 필요시 Router에 user 전달해서 인증 여부에 따라 라우팅을 제어해야 한다. 

❌ 주의사항

  1. App() 함수 안에서 useState와 useEffect를 선언해야 한다. 
  2. handleLogout() 함수도 App() 함수 범위 밖에 있으면 동작이 안된다.
  3. user 상태도 App()이나 Router() 내부에서 써야 한다. 
  4. 인증 상태를 추적하고 싶다면 App()이나 Router() 컴포넌트 안에서 user 상태를 관리해야 한다.
/* client/src/App.tsx */

import { useEffect, useState } from "react";
import Auth from "@/pages/Auth";
import { onAuthStateChanged, signOut, User } from "firebase/auth";
import { auth } from "./pages/Firebase";

function Router({ user }: { user: User | null }) {
  const [location, setLocation] = useLocation();

  return (
      <Route path="/auth" component={Auth} />
  );
}

function App() {
  const [user, setUser] = useState<User | null>(null);

  const handleLogout = () => {
    signOut(auth)
      .then(() => {
        console.log("로그아웃 성공");
      })
      .catch((err) => {
        console.error("로그아웃 실패:", err);
      });
  };

  return (
    <Router user={user} />
  );
}

export default App;

🧪 6. Google 로그인 핸들러 함수 만들기

✅ 목표

  • Google 로그인 버튼을 누르면 Firebase Auth를 통해 로그인
  • 로그인 성공 시 sessionStorage 저장 및 setLocation()으로 리다이렉트
  • 실패 시 토스트로 에러 표시
/* client/src/pages/Auth.tsx */

import { GoogleAuthProvider, signInWithPopup } from "firebase/auth";
import { auth, provider } from "./Firebase";

const handleLogin = async () => {
    const provider = new GoogleAuthProvider();

    try {
      const result = await signInWithPopup(auth, provider);
      const user = result.user;

      // 세션에 사용자 정보 저장
      sessionStorage.setItem("userInfo", JSON.stringify(user));
      console.log("로그인 성공:", user);
          
      // 페이지 이동 등 처리
      setLocation("/post-preview");
    } catch (error) {
      console.error("Google 로그인 실패:", error);
      toast({
        title: "Google 로그인 실패",
        description:
          error instanceof Error
            ? error.message
            : "문제가 발생했어요. 다시 시도해주세요!",
        variant: "destructive",
      });
    }
  };

🖼 7. Google 아이콘 버튼과 함께 로그인 UI 만들기

/* client/src/pages/Auth.tsx */

return (
    <Button
      type="button"
      onClick={handleLogin}
      className="w-full mt-2 gap-2"
      variant="outline"
      disabled={isLoading}
    >
      <img
        src="https://www.gstatic.com/firebasejs/ui/2.0.0/images/auth/google.svg"
        alt="Google Logo"
        className="w-5 h-5"
      />
      Continue with Google
    </Button>
)
/* client/src/components/ui/google-login-button.tsx */

import { signInWithPopup } from "firebase/auth";
import { auth, provider } from "../../pages/Firebase";

const LoginButton = () => {
  const handleLogin = async () => {
    try {
      const result = await signInWithPopup(auth, provider);
      const user = result.user;
      console.log("User Info:", {
        name: user.displayName,
        email: user.email,
        photo: user.photoURL,
      });
    } catch (err) {
      console.error("Login Error:", err);
    }
  };

  return <button onClick={handleLogin}>Google로 로그인</button>;
};

export default LoginButton;

 


🔧 Firebase에 도메인 단계별 설정 방법

  1. Firebase Console 접속
  2. 해당 프로젝트 클릭
  3. 사이드바에서 Authentication > 설정 (Settings) 클릭
  4. "허용된 도메인(Authorized domains)" 섹션 찾기
  5. ✅ 아래 중 개발 중인 환경에 맞게 추가:
    • localhost (로컬 개발 중일 경우)
    • 127.0.0.1 (경우에 따라 localhost 대신 필요)
    • your-domain.com (실제 배포 주소)
    • replit.dev, vercel.app 같은 개발용 URL (해당되는 경우)

🚨 에러 종류

signInWithPopup 함수가 import되지 않았을 때

Google 로그인 실패
-> signInWithPopup is not defined

 

Firebase Authentication에서 허용하지 않은 도메인에서 로그인 요청이 들어왔을 때

Google 로그인 실패
-> firebase: error (auth/unauthorized-domain)

 

728x90