Google OAuth Implementation with Firebase - 🙏 Namaste React

0
Google OAuth Implementation with Firebase: Complete Guide

Google OAuth Implementation with Firebase

Series Note: This is part of our React Authentication series. Make sure to check out our previous guides:
Google OAuth with Firebase

Introduction

This guide builds upon our previous Redux Toolkit and Redux Persist implementations to create a complete authentication system using Google OAuth with Firebase. We'll cover both frontend and backend integration, focusing on secure and efficient implementation.

Firebase Setup and Configuration

Step-by-Step Firebase Setup

Before implementing Google OAuth, we need to set up Firebase in our project. Here's the detailed process:

Firebase Project Setup:
  1. Navigate to Firebase Console
  2. Access the main console interface
  3. Create a new project
  4. Look for the web icon (</>) in the dashboard
  5. Register your app and activate the configuration and add the configuration code in a src folder . Discussed in the Front-End Intergration.

Frontend Integration

After setting up the Firebase project, we need to integrate it into our frontend:

  1. Install Firebase in your project:
    npm install firebase
  2. Create firebaseConfig.js in your src root folder
  3. Configure environment variables for sensitive data
  4. Security Note: The configuration variables (shown in green in Firebase console) should be stored in your .env file for security.
  5. firebaseConfig.js
  6. 
                  // Import the functions you need from the SDKs you need
    import { initializeApp } from "firebase/app";
    import { getAnalytics } from "firebase/analytics";
    // TODO: Add SDKs for Firebase products that you want to use
    // https://firebase.google.com/docs/web/setup#available-libraries
    
    // Your web app's Firebase configuration
    // For Firebase JS SDK v7.20.0 and later, measurementId is optional
    const firebaseConfig = {
      apiKey: import.meta.env.VITE_FIREBASE_apiKey,
      authDomain: import.meta.env.VITE_FIREBASE_authDomain,
      projectId: import.meta.env.VITE_FIREBASE_projectId,
      storageBucket: import.meta.env.VITE_FIREBASE_storageBucket,
      messagingSenderId: import.meta.env.VITE_FIREBASE_messagingSenderId,
      appId: import.meta.env.VITE_FIREBASE_appId,
      measurementId: import.meta.env.VITE_FIREBASE_measurementId
    };
    
    // Initialize Firebase
    export const app = initializeApp(firebaseConfig);
                  

Authentication Logic Implementation

After configuration, we implement the authentication logic:

  1. Import and set up Google Auth Provider:
    
    import { GoogleAuthProvider, getAuth } from 'firebase/auth';
    
    const provider = new GoogleAuthProvider();
    provider.setCustomParameters({
        prompt: 'select_account'  // Ensures account selection prompt
    });
  2. Initialize Firebase auth:
    
    import { app } from '../firebaseConfig';
    const auth = getAuth(app);
  3. Implement sign-in logic:
    
    const handleGoogleSignIn = async () => {
        try {
            const result = await signInWithPopup(auth, provider);
            // Process authentication result
        } catch (error) {
            console.error('Authentication error:', error);
        }
    };

Backend Integration and State Management

Backend Authentication Flow

The backend handles user authentication through a sophisticated flow:

  1. Receive Google OAuth data from frontend
  2. Check if user exists in database
  3. If user exists:
    • Generate JWT token
    • Send user data back to frontend
  4. If user doesn't exist:
    • Create new user record
    • Generate secure password hash
    • Save user with profile photo
    • Generate JWT token
Implementation Note: The backend controller handles both new and existing users seamlessly:

export const googleouth = async (req, res, next) => {
    const { email, displayName, photoURL } = req.body;
    try {
        const user = await User.findOne({email});
        if(user){
            // Handle existing user
            const token = jwt.sign({id:user._id}, process.env.JWT_SECRET);
            // ... token handling
        } else {
            // Create new user
            const newUser = new User({
                username: displayName.toLowerCase().split(' ').join('') + 
                    Math.random().toString(9).slice(-4),
                email,
                photoURL,
            });
            // ... user creation and token generation
        }
    } catch(error) {
        next(errorHandler(500, 'Internal Server Error'));
    }
};

Redux Integration

After successful authentication, we integrate with Redux Toolkit for state management:


import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { signInSuccess } from '../redux/user/authSlice';

// In your component
const dispatch = useDispatch();
const navigate = useNavigate();

// After successful authentication
if(response.status === 200){
    dispatch(signInSuccess(response.data));
    navigate('/');
}

Frequently Asked Questions

1. How do you handle children props in React components?

React components accept children props for flexible content rendering:


const CustomComponent = ({ children, ...props }) => (
    <div {...props}>
        {children}
    </div>
);

// Usage
<CustomComponent
    className="custom-class"
>
    <p>This is a custom component</p>
</CustomComponent>
            

2. What are the best practices for implementing Google OAuth?

Key considerations include:

  • Using environment variables for Firebase configuration
  • Implementing proper error handling and loading states
  • Securing user data and tokens
  • Following OAuth 2.0 best practices
  • Implementing proper state management with Redux Toolkit

3. How do you handle authentication errors?

Implement comprehensive error handling:


try {
    const result = await signInWithPopup(auth, provider);
    // Handle successful authentication
} catch (error) {
    switch (error.code) {
        case 'auth/popup-closed-by-user':
            console.log('User closed the popup');
            break;
        case 'auth/cancelled-popup-request':
            console.log('Multiple popup requests');
            break;
        default:
            console.error('Authentication error:', error);
    }
}
            

4. How do you ensure secure token storage?

Best practices for token storage include:

  • Using HTTP-only cookies for JWT storage
  • Implementing proper token expiration
  • Using secure and sameSite cookie attributes
  • Never storing sensitive data in localStorage

Source Code & Commits

Access the complete source code and implementation details:

Note: Check out the complete project repository for the latest updates and improvements.

If You Face Any Issues, Feel Free to Connect With Me

Post a Comment

0Comments
Post a Comment (0)
To Top