Skip to main content
RapidDev - Software Development Agency
firebase-tutorial

How to Set Up Firebase Authentication With Google Sign-In

Firebase Auth with Google Sign-In uses the GoogleAuthProvider and signInWithPopup() for a seamless OAuth login flow. Enable Google as a sign-in provider in the Firebase Console, initialize the provider in your app, and call signInWithPopup(auth, provider) to open the Google login dialog. Use onAuthStateChanged() to track the user session and write Firestore security rules that require request.auth for protected data.

What you'll learn

  • How to enable Google as a sign-in provider in the Firebase Console
  • How to implement Google sign-in with signInWithPopup and handle the result
  • How to track authentication state with onAuthStateChanged and protect routes
  • How to write Firestore security rules that require authenticated users
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate11 min read15-20 minFirebase Auth (Spark and Blaze plans), firebase/auth v9+ modular SDK, all modern browsersMarch 2026RapidDev Engineering Team
TL;DR

Firebase Auth with Google Sign-In uses the GoogleAuthProvider and signInWithPopup() for a seamless OAuth login flow. Enable Google as a sign-in provider in the Firebase Console, initialize the provider in your app, and call signInWithPopup(auth, provider) to open the Google login dialog. Use onAuthStateChanged() to track the user session and write Firestore security rules that require request.auth for protected data.

Adding Google Sign-In to Your Web App With Firebase Auth

Google Sign-In is the most popular OAuth provider for Firebase Auth. It lets users log in with their existing Google account in one click, without creating a new password. Firebase handles the entire OAuth flow, token management, and session persistence. This tutorial covers enabling the provider, implementing the sign-in flow, managing auth state, storing additional user data in Firestore, and securing your database with authentication-based rules.

Prerequisites

  • A Firebase project created in the Firebase Console
  • Firebase JS SDK installed in your web app (npm install firebase)
  • Firebase initialized with initializeApp() and your project config
  • Basic knowledge of React or vanilla JavaScript for the frontend

Step-by-step guide

1

Enable Google as a sign-in provider in the Firebase Console

Go to the Firebase Console, select your project, and navigate to Authentication > Sign-in method. Click Google in the provider list and toggle the Enable switch. Enter a public-facing name for your app (shown on the consent screen) and select a support email address. Click Save. Firebase automatically configures the OAuth client ID and secret — you do not need to create these manually in the Google Cloud Console.

typescript
1// Firebase Console steps:
2// 1. Go to console.firebase.google.com
3// 2. Select your project
4// 3. Click Authentication in the left sidebar
5// 4. Click the "Sign-in method" tab
6// 5. Click "Google" in the provider list
7// 6. Toggle "Enable" to on
8// 7. Enter your app name (shown on consent screen)
9// 8. Select a support email
10// 9. Click Save
11
12// After enabling, verify your authorized domains:
13// Authentication > Settings > Authorized domains
14// Ensure localhost and your production domain are listed

Expected result: Google appears as an enabled sign-in provider with a green checkmark in the Firebase Console.

2

Initialize Firebase Auth and GoogleAuthProvider

Import getAuth and GoogleAuthProvider from the firebase/auth module. Initialize the auth instance and create a provider. You can optionally add scopes to request additional Google API permissions (like Google Calendar or Drive access) and set custom parameters to control the consent screen behavior.

typescript
1import { initializeApp } from "firebase/app";
2import {
3 getAuth,
4 GoogleAuthProvider,
5 signInWithPopup,
6 signOut,
7 onAuthStateChanged,
8 type User,
9} from "firebase/auth";
10
11const firebaseConfig = {
12 apiKey: "your-api-key",
13 authDomain: "your-project.firebaseapp.com",
14 projectId: "your-project",
15 storageBucket: "your-project.appspot.com",
16 messagingSenderId: "123456789",
17 appId: "1:123456789:web:abc123",
18};
19
20const app = initializeApp(firebaseConfig);
21const auth = getAuth(app);
22
23// Create Google provider with optional scopes
24const googleProvider = new GoogleAuthProvider();
25googleProvider.addScope("profile");
26googleProvider.addScope("email");
27
28// Optional: force account selection every time
29googleProvider.setCustomParameters({
30 prompt: "select_account",
31});
32
33export { auth, googleProvider };

Expected result: Firebase Auth and GoogleAuthProvider are initialized and ready for sign-in calls.

3

Implement the Google sign-in flow with signInWithPopup

Call signInWithPopup(auth, googleProvider) to open a popup window where the user selects their Google account. The function returns a UserCredential object containing the user's profile (displayName, email, photoURL, uid) and an OAuth access token. Handle errors gracefully — common error codes include auth/popup-closed-by-user and auth/popup-blocked.

typescript
1import { auth, googleProvider } from "./firebase-config";
2import { signInWithPopup, GoogleAuthProvider } from "firebase/auth";
3
4async function signInWithGoogle() {
5 try {
6 const result = await signInWithPopup(auth, googleProvider);
7
8 // The signed-in user
9 const user = result.user;
10 console.log("Signed in as:", user.displayName);
11 console.log("Email:", user.email);
12 console.log("Photo:", user.photoURL);
13 console.log("UID:", user.uid);
14
15 // Google OAuth access token (for Google APIs, if needed)
16 const credential = GoogleAuthProvider.credentialFromResult(result);
17 const accessToken = credential?.accessToken;
18
19 return user;
20 } catch (error: any) {
21 if (error.code === "auth/popup-closed-by-user") {
22 console.log("User closed the popup");
23 } else if (error.code === "auth/popup-blocked") {
24 console.log("Popup was blocked by the browser");
25 // Fall back to redirect flow
26 } else {
27 console.error("Sign-in error:", error.message);
28 }
29 return null;
30 }
31}

Expected result: Clicking the sign-in button opens a Google account picker. After selection, the user is authenticated and their profile is available.

4

Track auth state with onAuthStateChanged

onAuthStateChanged fires whenever the authentication state changes — when a user signs in, signs out, or when the page loads with an existing session. Use it to update your UI, protect routes, and gate access to features. Always wait for onAuthStateChanged before querying Firestore, since auth.currentUser may be null during initialization.

typescript
1import { auth } from "./firebase-config";
2import { onAuthStateChanged, type User } from "firebase/auth";
3
4// Global auth state
5let currentUser: User | null = null;
6
7// Listen for auth state changes
8const unsubscribe = onAuthStateChanged(auth, (user) => {
9 currentUser = user;
10
11 if (user) {
12 console.log("User is signed in:", user.displayName);
13 // Show authenticated UI
14 // Redirect to dashboard
15 // Fetch user-specific data from Firestore
16 } else {
17 console.log("User is signed out");
18 // Show sign-in button
19 // Redirect to login page
20 }
21});
22
23// Wait for auth to initialize before querying Firestore
24function waitForAuth(): Promise<User | null> {
25 return new Promise((resolve) => {
26 const unsub = onAuthStateChanged(auth, (user) => {
27 unsub(); // Unsubscribe after first emission
28 resolve(user);
29 });
30 });
31}
32
33// Usage:
34// const user = await waitForAuth();
35// if (user) { /* fetch protected data */ }

Expected result: Your app reacts to auth state changes, showing the right UI for signed-in and signed-out users.

5

Store additional user data in Firestore on first sign-in

Firebase Auth stores basic profile info (name, email, photo). For additional data like roles, preferences, or app-specific fields, create a Firestore document for each user. Check if the document exists after sign-in — if not, create it. Use the user's UID as the document ID for easy lookups. Write security rules that require the user to be authenticated and match the document owner.

typescript
1import { doc, getDoc, setDoc, serverTimestamp } from "firebase/firestore";
2import { db } from "./firebase-config";
3import { type User } from "firebase/auth";
4
5async function ensureUserProfile(user: User) {
6 const userRef = doc(db, "users", user.uid);
7 const userDoc = await getDoc(userRef);
8
9 if (!userDoc.exists()) {
10 // First sign-in — create the profile
11 await setDoc(userRef, {
12 displayName: user.displayName,
13 email: user.email,
14 photoURL: user.photoURL,
15 role: "user",
16 createdAt: serverTimestamp(),
17 lastLogin: serverTimestamp(),
18 });
19 } else {
20 // Returning user — update last login
21 await setDoc(userRef, { lastLogin: serverTimestamp() }, { merge: true });
22 }
23}
24
25// Call after successful sign-in:
26// const user = await signInWithGoogle();
27// if (user) await ensureUserProfile(user);

Expected result: A Firestore document at users/{uid} stores the user's profile and is created automatically on first Google sign-in.

6

Write Firestore security rules that require authentication

Protect your Firestore data by writing security rules that check request.auth. This ensures that only authenticated users can read and write data, and users can only access their own documents. Deploy rules with firebase deploy --only firestore:rules.

typescript
1// firestore.rules
2rules_version = '2';
3service cloud.firestore {
4 match /databases/{database}/documents {
5
6 // User profiles: owner can read/write, others can read
7 match /users/{userId} {
8 allow read: if request.auth != null;
9 allow write: if request.auth != null
10 && request.auth.uid == userId;
11 }
12
13 // User-owned data: only the owner can access
14 match /todos/{todoId} {
15 allow read, write: if request.auth != null
16 && request.auth.uid == resource.data.userId;
17 allow create: if request.auth != null
18 && request.auth.uid == request.resource.data.userId;
19 }
20
21 // Public data: anyone authenticated can read
22 match /posts/{postId} {
23 allow read: if request.auth != null;
24 allow create: if request.auth != null
25 && request.auth.uid == request.resource.data.authorId;
26 allow update, delete: if request.auth != null
27 && request.auth.uid == resource.data.authorId;
28 }
29 }
30}

Expected result: Firestore data is protected by authentication rules. Unauthenticated users cannot read or write any data.

7

Implement sign-out

Call signOut(auth) to sign the user out. This clears the Firebase Auth session, triggers onAuthStateChanged with a null user, and invalidates the ID token. Redirect the user to the login page or update the UI to show the signed-out state. Clean up any local state or cached data related to the user.

typescript
1import { signOut } from "firebase/auth";
2import { auth } from "./firebase-config";
3
4async function handleSignOut() {
5 try {
6 await signOut(auth);
7 // onAuthStateChanged will fire with null user
8 // Your auth state listener handles the UI update
9 console.log("Signed out successfully");
10
11 // Optional: clear local state
12 // localStorage.removeItem("userPreferences");
13 // Navigate to login page
14 } catch (error) {
15 console.error("Sign-out error:", error);
16 }
17}

Expected result: The user is signed out, onAuthStateChanged fires with null, and the UI shows the signed-out state.

Complete working example

auth.ts
1// Firebase Auth — Google Sign-In Complete Implementation
2import { initializeApp } from "firebase/app";
3import {
4 getAuth,
5 GoogleAuthProvider,
6 signInWithPopup,
7 signInWithRedirect,
8 signOut,
9 onAuthStateChanged,
10 type User,
11} from "firebase/auth";
12import {
13 getFirestore,
14 doc,
15 getDoc,
16 setDoc,
17 serverTimestamp,
18} from "firebase/firestore";
19
20const firebaseConfig = {
21 apiKey: "your-api-key",
22 authDomain: "your-project.firebaseapp.com",
23 projectId: "your-project",
24 storageBucket: "your-project.appspot.com",
25 messagingSenderId: "123456789",
26 appId: "1:123456789:web:abc123",
27};
28
29const app = initializeApp(firebaseConfig);
30export const auth = getAuth(app);
31export const db = getFirestore(app);
32
33const googleProvider = new GoogleAuthProvider();
34googleProvider.addScope("profile");
35googleProvider.addScope("email");
36googleProvider.setCustomParameters({ prompt: "select_account" });
37
38// Sign in with Google
39export async function signInWithGoogle(): Promise<User | null> {
40 try {
41 const result = await signInWithPopup(auth, googleProvider);
42 await ensureUserProfile(result.user);
43 return result.user;
44 } catch (error: any) {
45 if (error.code === "auth/popup-blocked") {
46 await signInWithRedirect(auth, googleProvider);
47 return null;
48 }
49 if (error.code !== "auth/popup-closed-by-user") {
50 console.error("Sign-in error:", error.code, error.message);
51 }
52 return null;
53 }
54}
55
56// Create or update user profile in Firestore
57async function ensureUserProfile(user: User) {
58 const userRef = doc(db, "users", user.uid);
59 const userDoc = await getDoc(userRef);
60 if (!userDoc.exists()) {
61 await setDoc(userRef, {
62 displayName: user.displayName,
63 email: user.email,
64 photoURL: user.photoURL,
65 role: "user",
66 createdAt: serverTimestamp(),
67 lastLogin: serverTimestamp(),
68 });
69 } else {
70 await setDoc(userRef, { lastLogin: serverTimestamp() }, { merge: true });
71 }
72}
73
74// Sign out
75export async function handleSignOut() {
76 await signOut(auth);
77}
78
79// Auth state listener
80export function onAuthChange(callback: (user: User | null) => void) {
81 return onAuthStateChanged(auth, callback);
82}
83
84// Wait for auth initialization
85export function waitForAuth(): Promise<User | null> {
86 return new Promise((resolve) => {
87 const unsub = onAuthStateChanged(auth, (user) => {
88 unsub();
89 resolve(user);
90 });
91 });
92}

Common mistakes when setting up Firebase Authentication With Google Sign-In

Why it's a problem: Querying Firestore before onAuthStateChanged resolves, getting 'Missing or insufficient permissions' because auth.currentUser is still null

How to avoid: Always wait for onAuthStateChanged to fire before making Firestore queries. Use a Promise wrapper or auth state context provider to ensure auth is initialized.

Why it's a problem: Not adding the production domain to Firebase Console's Authorized domains, causing sign-in to fail after deployment

How to avoid: Go to Authentication > Settings > Authorized domains and add your production domain. Firebase only allows sign-in from listed domains.

Why it's a problem: Using signInWithRedirect without calling getRedirectResult() on page load, causing the sign-in result to be silently lost

How to avoid: If you use signInWithRedirect, call getRedirectResult(auth) when the page loads to capture the authentication result after the redirect completes.

Why it's a problem: Not writing Firestore security rules that check request.auth, leaving data accessible to anyone with the project's API key

How to avoid: Write security rules that require request.auth != null for every collection. The API key is public — security rules are your only protection for Firestore data.

Best practices

  • Always wait for onAuthStateChanged before querying Firestore to avoid permission errors during auth initialization
  • Use signInWithPopup as the primary flow and fall back to signInWithRedirect when the popup is blocked
  • Set prompt: 'select_account' on the Google provider so users can choose which account to sign in with
  • Store a user profile document in Firestore at users/{uid} for app-specific data beyond basic Auth profile
  • Write Firestore security rules that check request.auth.uid matches the document owner for all write operations
  • Clean up onAuthStateChanged listeners when components unmount to prevent memory leaks
  • Add your production domain to the Firebase Console's Authorized domains list before deploying
  • Handle common error codes (popup-closed-by-user, popup-blocked) gracefully in your UI

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I want to add Google Sign-In to my React web app using Firebase Auth. Write a complete authentication module with: signInWithPopup (with redirect fallback), onAuthStateChanged listener, sign-out function, a Firestore user profile that is created on first sign-in, and Firestore security rules that require authentication for all data access. Use the modular v9 Firebase SDK with TypeScript.

Firebase Prompt

Set up Firebase Authentication with Google Sign-In in my web app. Create a GoogleAuthProvider with select_account prompt, implement signInWithPopup with error handling, add an onAuthStateChanged listener, create a Firestore user profile on first login with displayName, email, photoURL, role, and timestamps. Include Firestore security rules that restrict access to authenticated users.

Frequently asked questions

Is Google Sign-In free with Firebase Auth?

Yes. Firebase Auth with Google Sign-In is free on both the Spark and Blaze plans for unlimited users. There are no per-authentication charges for OAuth providers.

Why does signInWithPopup fail on mobile Safari?

Mobile Safari blocks popups by default unless they are triggered by a direct user gesture (click). Ensure signInWithPopup is called directly inside a click event handler, not in an async chain. If it still fails, fall back to signInWithRedirect.

Can I get the user's Google access token for Google APIs?

Yes. After signInWithPopup, call GoogleAuthProvider.credentialFromResult(result) to get the OAuth credential, which contains the access token. Add Google API scopes to the provider with addScope() to request specific permissions.

What happens when a user signs in with Google and then with email/password using the same email?

By default, Firebase links accounts with the same email address. The user can then sign in with either method. You can change this behavior in Authentication > Settings > User actions by disabling 'Multiple accounts per email address'.

How do I restrict Google sign-in to specific email domains?

Firebase Auth does not restrict domains natively. Use a Blocking Function (beforeCreate) on the server side to check the user's email domain and reject sign-ups from unauthorized domains. Alternatively, check the domain in your app code after sign-in and sign the user out if unauthorized.

Does Firebase handle token refresh automatically?

Yes. Firebase Auth automatically refreshes the ID token (which expires every hour) using a long-lived refresh token stored in the browser. You do not need to handle token refresh manually. The onAuthStateChanged listener keeps working across refreshes.

Can RapidDev help implement Firebase Auth with Google login?

Yes. RapidDev can set up Firebase Auth with Google Sign-In, build a complete authentication flow with protected routes, create Firestore user profiles, write security rules, and integrate with your existing app architecture.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.