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
Enable Google as a sign-in provider in the Firebase Console
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.
1// Firebase Console steps:2// 1. Go to console.firebase.google.com3// 2. Select your project4// 3. Click Authentication in the left sidebar5// 4. Click the "Sign-in method" tab6// 5. Click "Google" in the provider list7// 6. Toggle "Enable" to on8// 7. Enter your app name (shown on consent screen)9// 8. Select a support email10// 9. Click Save1112// After enabling, verify your authorized domains:13// Authentication > Settings > Authorized domains14// Ensure localhost and your production domain are listedExpected result: Google appears as an enabled sign-in provider with a green checkmark in the Firebase Console.
Initialize Firebase Auth and GoogleAuthProvider
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.
1import { initializeApp } from "firebase/app";2import {3 getAuth,4 GoogleAuthProvider,5 signInWithPopup,6 signOut,7 onAuthStateChanged,8 type User,9} from "firebase/auth";1011const 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};1920const app = initializeApp(firebaseConfig);21const auth = getAuth(app);2223// Create Google provider with optional scopes24const googleProvider = new GoogleAuthProvider();25googleProvider.addScope("profile");26googleProvider.addScope("email");2728// Optional: force account selection every time29googleProvider.setCustomParameters({30 prompt: "select_account",31});3233export { auth, googleProvider };Expected result: Firebase Auth and GoogleAuthProvider are initialized and ready for sign-in calls.
Implement the Google sign-in flow with signInWithPopup
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.
1import { auth, googleProvider } from "./firebase-config";2import { signInWithPopup, GoogleAuthProvider } from "firebase/auth";34async function signInWithGoogle() {5 try {6 const result = await signInWithPopup(auth, googleProvider);78 // The signed-in user9 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);1415 // Google OAuth access token (for Google APIs, if needed)16 const credential = GoogleAuthProvider.credentialFromResult(result);17 const accessToken = credential?.accessToken;1819 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 flow26 } 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.
Track auth state with onAuthStateChanged
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.
1import { auth } from "./firebase-config";2import { onAuthStateChanged, type User } from "firebase/auth";34// Global auth state5let currentUser: User | null = null;67// Listen for auth state changes8const unsubscribe = onAuthStateChanged(auth, (user) => {9 currentUser = user;1011 if (user) {12 console.log("User is signed in:", user.displayName);13 // Show authenticated UI14 // Redirect to dashboard15 // Fetch user-specific data from Firestore16 } else {17 console.log("User is signed out");18 // Show sign-in button19 // Redirect to login page20 }21});2223// Wait for auth to initialize before querying Firestore24function waitForAuth(): Promise<User | null> {25 return new Promise((resolve) => {26 const unsub = onAuthStateChanged(auth, (user) => {27 unsub(); // Unsubscribe after first emission28 resolve(user);29 });30 });31}3233// 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.
Store additional user data in Firestore on first sign-in
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.
1import { doc, getDoc, setDoc, serverTimestamp } from "firebase/firestore";2import { db } from "./firebase-config";3import { type User } from "firebase/auth";45async function ensureUserProfile(user: User) {6 const userRef = doc(db, "users", user.uid);7 const userDoc = await getDoc(userRef);89 if (!userDoc.exists()) {10 // First sign-in — create the profile11 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 login21 await setDoc(userRef, { lastLogin: serverTimestamp() }, { merge: true });22 }23}2425// 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.
Write Firestore security rules that require authentication
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.
1// firestore.rules2rules_version = '2';3service cloud.firestore {4 match /databases/{database}/documents {56 // User profiles: owner can read/write, others can read7 match /users/{userId} {8 allow read: if request.auth != null;9 allow write: if request.auth != null10 && request.auth.uid == userId;11 }1213 // User-owned data: only the owner can access14 match /todos/{todoId} {15 allow read, write: if request.auth != null16 && request.auth.uid == resource.data.userId;17 allow create: if request.auth != null18 && request.auth.uid == request.resource.data.userId;19 }2021 // Public data: anyone authenticated can read22 match /posts/{postId} {23 allow read: if request.auth != null;24 allow create: if request.auth != null25 && request.auth.uid == request.resource.data.authorId;26 allow update, delete: if request.auth != null27 && 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.
Implement sign-out
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.
1import { signOut } from "firebase/auth";2import { auth } from "./firebase-config";34async function handleSignOut() {5 try {6 await signOut(auth);7 // onAuthStateChanged will fire with null user8 // Your auth state listener handles the UI update9 console.log("Signed out successfully");1011 // Optional: clear local state12 // localStorage.removeItem("userPreferences");13 // Navigate to login page14 } 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
1// Firebase Auth — Google Sign-In Complete Implementation2import { 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";1920const 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};2829const app = initializeApp(firebaseConfig);30export const auth = getAuth(app);31export const db = getFirestore(app);3233const googleProvider = new GoogleAuthProvider();34googleProvider.addScope("profile");35googleProvider.addScope("email");36googleProvider.setCustomParameters({ prompt: "select_account" });3738// Sign in with Google39export 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}5556// Create or update user profile in Firestore57async 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}7374// Sign out75export async function handleSignOut() {76 await signOut(auth);77}7879// Auth state listener80export function onAuthChange(callback: (user: User | null) => void) {81 return onAuthStateChanged(auth, callback);82}8384// Wait for auth initialization85export 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.
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.
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.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation