Introduction
User authentication is an important feature in all modern web applications. Whether they are e-commerce sites, social platforms, or business applications, web applications need to give users secure and convenient ways to log-in. In this three-part article, we are going to show you how to implement some of the popular logging-in methods by utilizing Firebase, React, TypeScript, and Material-UI. In Part One (this article), we are going to set up Google Authentication, which is the quickest way of allowing users to sign-in with their google account they already have, and by the end of this article we are going to have a working Google Sign-In in your React app.
Why Choose Firebase Authentication?
Firebase Authentication offers several advantages :
- Easy Integration : Minimal setup required
- Multiple Providers : Google, Facebook, Twitter, GitHub, and more
- Security : Built-in security features and best practices
- Scalability : Handles millions of users without additional configuration
- Free Tier : Generous free usage limits
- Real-time Updates : Instant authentication state changes
What will we create?
We will create a stunning UI as shown in this video, building it in three parts, so follow along till the end.
Prerequisites
- Node.js (version 16 or higher) – Download here
- npm or yarn package manager
- A Google account for Firebase Console access
- Basic understanding of React and JavaScript/TypeScript
- A code editor like VS Code
Don’t worry if you’re new to TypeScript or Firebase – we’ll explain everything step by step!
Setting Up Firebase
Step 1 : Create Your Firebase Project
- Visit the Firebase Console
- Click the “Create a project” button
- Enter a project name (e.g., “my-auth-app”)
- Choose whether to enable Google Analytics (recommended for production apps)
- Click “Create project” and wait for setup to complete
Step 2 : Enable Authentication Methods
- In your Firebase project dashboard, click “Authentication” in the left sidebar
- Go to the “Sign-in method” tab
- Enable the following providers:
For Google :
- Click on “Google”.
- Toggle “Enable”.
- Select your project support email.
- Click “Save”.
Step 3 : Get Your Firebase Configuration
- Click the gear icon ⚙️ next to “Project Overview”.
- Select “Project settings”.
- Scroll to “Your apps” section.
- Click the web icon </>.
- Register your app with a nickname.
- Copy the configuration object (we’ll use this later).
Creating the React TypeScript Project
Let’s create our project with all necessary dependencies :
//Create a new react app using the following command
npm create vite@latest firebase-auth-demo -- --template react-ts
# Navigate to the project directory
cd firebase-auth-app
# Install required dependencies
npm install firebase @mui/material @emotion/react @emotion/styled @mui/icons-material @mui/lab
# Start the development server
npm run dev
Your browser should open automatically showing the default React app. If not, visit – http://localhost:5173.
Folder Structure :
src/
├── components/
│ ├── auth/
│ │ ├── GoogleAuth.tsx
│ │ └── AuthenticationContainer.tsx
│ └── Dashboard.tsx
├── contexts/
│ └── AuthContext.tsx
├── services/
│ └── authService.ts
├── config/
│ └── firebase.ts
└── App.tsx
Firebase Configuration
Create src/config/firebase.ts :
import { initializeApp } from 'firebase/app';
import { getAuth, GoogleAuthProvider} from 'firebase/auth';
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = {
apiKey: "your-api-key",
authDomain: "your-project.firebaseapp.com",
projectId: "your-project-id",
storageBucket: "your-project.appspot.com",
messagingSenderId: "your-sender-id",
appId: "your-app-id"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
// Initialize Firebase Authentication and get a reference to the service
export const auth = getAuth(app);
// Initialize Firestore
export const db = getFirestore(app);
// Configure providers
export const googleProvider = new GoogleAuthProvider();
export default app;
Authentication Service
Create src/services/authService.ts :
import { signInWithPopup, type User, signOut as firebaseSignOut, onAuthStateChanged } from "firebase/auth";
import { auth, googleProvider } from '../config/firebase';
export interface AuthUser {
uid: string;
email: string | null;
displayName: string | null;
photoURL: string | null;
phoneNumber: string | null;
}
class AuthService {
// Google Sign In
async signInWithGoogle(): Promise {
try {
const result = await signInWithPopup(auth, googleProvider);
return this.formatUser(result.user);
} catch (error) {
console.error('Google sign in error:', error);
throw error;
}
}
// Sign Out
async signOut(): Promise {
try {
await firebaseSignOut(auth);
this.cleanup();
} catch (error) {
console.error('Sign out error:', error);
throw error;
}
}
// Listen to auth state changes
onAuthStateChange(callback: (user: AuthUser | null) => void): () => void {
return onAuthStateChanged(auth, (user) => {
callback(user ? this.formatUser(user) : null);
});
}
// Format user object
private formatUser(user: User): AuthUser {
return {
uid: user.uid,
email: user.email,
displayName: user.displayName,
photoURL: user.photoURL,
};
}
export default new AuthService();
Understanding Key Functions
- signInWithPopup() :
This Firebase function opens a popup window for Google OAuth. It handles the entire OAuth flow and returns user credentials upon successful authentication.
- onAuthStateChanged() :
A Firebase listener that monitors authentication state changes. It automatically updates your app when users sign in or out, ensuring consistent state management.
- GoogleAuthProvider() :
Firebase’s built-in provider for Google OAuth. You can add specific scopes (like ’email’, ‘profile’) to request additional permissions.
- Context Pattern:
React Context provides global authentication state management, avoiding prop drilling and ensuring any component can access user data.
- Error Handling :
The implementation includes comprehensive error handling for common scenarios :
- Popup blocked by browser
- User cancels sign-in
- Network connectivity issues
- Invalid configurations
Authentication Context
Create src/contexts/AuthContext.tsx :
import React, { createContext, useContext, useEffect, useState, type ReactNode } from 'react';
import authService, { type AuthUser } from '../services/authService';
interface AuthContextType {
user: AuthUser | null;
loading: boolean;
signInWithGoogle: () => Promise;
signOut: () => Promise;
}
const AuthContext = createContext(undefined);
export const useAuth = (): AuthContextType => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};
interface AuthProviderProps {
children: ReactNode;
}
export const AuthProvider: React.FC = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = authService.onAuthStateChange((user) => {
setUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
const signInWithGoogle = async (): Promise => {
try {
await authService.signInWithGoogle();
} catch (error) {
console.error('Google sign in failed:', error);
throw error;
}
};
const signOut = async (): Promise => {
try {
await authService.signOut();
} catch (error) {
console.error('Sign out failed:', error);
throw error;
}
};
const value = { user, loading, signInWithGoogle, signOut };
return {children} ;
};
Individual Authentication Components
GoogleAuth Component
Step 1 : Configure Google OAuth (Additional Setup)
Visit Google Cloud Console
Select your Firebase project
Go to “APIs & Services” → “Credentials”
Find your OAuth 2.0 Client ID (created automatically by Firebase)
Add your development URL (http://localhost:3000) to “Authorized origins”
For production, add your actual domain
Step 2 : Create Google Authentication Component
Create src/components/auth/GoogleAuth.tsx :
// GoogleAuth.tsx
import { useAuth } from '../../contexts/AuthContext';
const GoogleAuth: React.FC = () => {
const { signInWithGoogle } = useAuth();
// here you can manage loading and errors etc.
const handleGoogleSignIn = async () => {
try {
await signInWithGoogle();
} catch (err: any) {
setError(err.message || 'Google sign in failed');
}
};
return (
);
};
export default GoogleAuth;
Authentication Container Component
Create src/components/auth/AuthenticationContainer.tsx :
// AuthenticationContainer.tsx
import React from "react";
import GoogleAuth from "./GoogleAuth";
// import UI elements from material-UI as you need….
const AuthenticationContainer: React.FC = () => {
return (
Sign In
);
};
export default AuthenticationContainer;
Create Dashboard Component
src/components/Dashboard.tsx :
import React from "react";
import { Button, Typography, Box } from "@mui/material";
import { useAuth } from "../contexts/AuthContext";
const Dashboard: React.FC = () => {
const { user, signOut } = useAuth();
return (
Welcome, {user?.displayName || "User"}!
);
};
export default Dashboard;
Updated Main App Component
Update src/App.tsx :
// App.tsx
import React from "react";
import { CssBaseline, CircularProgress, Box, Typography } from "@mui/material";
import { ThemeProvider, createTheme } from "@mui/material/styles";
import { AuthProvider, useAuth } from "./contexts/AuthContext";
import AuthenticationContainer from "./components/auth/AuthenticationContainer";
import Dashboard from "./components/Dashboard";
const theme = createTheme({ // Customize theme as you need…..});
const LoadingScreen: React.FC = () => (// You can create this for better user experience….);
const AppContent: React.FC = () => {
const { user, loading } = useAuth();
if (loading) return ;
return user ? : ;
};
const App: React.FC = () => (
);
export default App;
Running the Application
npm run dev
Your application will be available at http://localhost:5173 with a complete authentication system supporting Google sign-in method.
Security Best Practices
- Environment Variables : Never commit API keys to version control.
- Firebase Security Rules : Implement proper Firestore security rules.
- App Check : Enable Firebase App Check for production apps.
- Input Validation : Always validate phone numbers and other inputs.
- Error Handling : Implement comprehensive error handling and user feedback.
Next Steps
This foundation provides a robust Google authentication system. You can extend it by :
- Adding user profile management.
- Implementing protected routes.
- Adding additional OAuth providers.
- Integrating with Firestore for user data.
The authentication service and context pattern make it easy to add Facebook and phone authentication, which we’ll cover in the next parts of this series.
Conclusion
This implementation creates a secure production-ready and fully configurable authentication module with various sign-in options. The modular structure allows for easy maintenance and extensibility, and TypeScript gives you the type safety throughout your application. Material UI gives you a professional and accessible user interface that works across all form factors.The authentication workflow accounts for edge cases and user feedback that can be useful in real-world applications.

