Firebase Authentication in React: Chapter 1 of Note Taking Series

Firebase Authentication in React: Chapter 1 of Note Taking Series

Oh! You finally made it to here. I know you want to learn full-stack and scale up your career and so do I. But hey, things take time and you should be consistent.
Welcome to the first chapter of my Note-Taking series called "Understanding Firebase Authentication" .

In the fast-paced world of web development, authentication is crucial for creating secure and personalized user experiences. Imagine building a food delivery app, where users need to create accounts, log in, and manage their orders. Firebase Authentication offers a streamlined solution for handling these authentication needs, allowing you to integrate login methods such as email/password and Google sign-in easily.
Let's walk through the steps of authentication.


Step 1: Setting Up Firebase

Before diving into the React app, let’s configure Firebase to handle authentication.

  1. Create a Firebase Account and Project:

    • Visit the Firebase Console, create an account (if you don't have one), and start a new project. Let's name it NoteTakingApp.
  2. Enable Authentication:

    • Inside your Firebase project dashboard, go to Authentication > Sign-in method, and enable Email/Password and Google Sign-In methods(I have used this two, you can choose whatever you want).

This will allow users to sign in using either email/password or their Google account to track their notes.

  1. Add a Web App:

    • In the Project Settings, click Add App and select Web. Firebase will provide you with the configuration needed to integrate it with React.

Step 2: Setting Up Your React App

  1. Create a New React App: Create a basic React app by running:

      npx create-react-app food-delivery-auth
    
  2. Install Firebase and Tailwind CSS: I have always said and used Tailwind in my projects as it offers clean and clear approach to style your elements. Install it and firebase using this command:

     npm install firebase
     npm install -D tailwindcss
     npx tailwindcss init
    
  3. Configure Tailwind: After installation, configure Tailwind to be used in your React app by adding the necessary settings in your tailwind.config.js file.


Step 3: Firebase Configuration

In your React app, you’ll need to set up Firebase connection.

  1. Create firebase.js in the src/firebase folder. You will get this boilerplate from your firebase web app setup as well:

     import { initializeApp } from "firebase/app";
     import { getAuth } from "firebase/auth";
    
     const firebaseConfig = {
       apiKey: "YOUR_API_KEY",
       authDomain: "YOUR_AUTH_DOMAIN",
       projectId: "YOUR_PROJECT_ID",
       storageBucket: "YOUR_STORAGE_BUCKET",
       messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
       appId: "YOUR_APP_ID"
     };
    
     const app = initializeApp(firebaseConfig);
     const auth = getAuth(app);
    
     export { app, auth };
    

This configuration connects your React app to Firebase, enabling authentication features.


Step 4: Authentication Context Setup

In our Note-Taking App, users will want to sign in to create, view, and manage their personal notes. For seamless access to user data and notes throughout the app, we’ll use React's Context API.

  1. Create an Authentication Context (src/contexts/AuthContext.js):

     import React, { useContext, useEffect, useState } from "react";
     import { auth } from "../firebase";
     import { onAuthStateChanged } from "firebase/auth";
    
     const AuthContext = React.createContext();
    
     export function useAuth() {
       return useContext(AuthContext);
     }
    
     export function AuthProvider({ children }) {
       const [currentUser, setCurrentUser] = useState(null);
       const [loading, setLoading] = useState(true);
    
       useEffect(() => {
         const unsubscribe = onAuthStateChanged(auth, (user) => {
           setCurrentUser(user);
           setLoading(false);
         });
    
         return unsubscribe;
       }, []);
    
       const value = {
         currentUser
       };
       return (
         <AuthContext.Provider value={value}>
           {!loading && children}
         </AuthContext.Provider>
       );
     }
    

This context will manage the authentication state across the entire app, ensuring the user’s login session persists when navigating between pages.


Step 5: Firebase Authentication Functions

Now, let’s define our authentication functions for signing in, signing up, and signing out.

  1. Create auth.js inside the src/firebase folder:

     import { createUserWithEmailAndPassword, signInWithEmailAndPassword, signInWithPopup, GoogleAuthProvider } from "firebase/auth";
     import { auth } from "./firebase";
    
     // Function for creating a new user with email and password
     export const registerWithEmail = (email, password) => {
       return createUserWithEmailAndPassword(auth, email, password);
     };
    
     // Function for signing in a user with email and password
     export const loginWithEmail = (email, password) => {
       return signInWithEmailAndPassword(auth, email, password);
     };
    
     // Function for signing in with Google
     export const loginWithGoogle = () => {
       const provider = new GoogleAuthProvider();
       return signInWithPopup(auth, provider);
     };
    
     // Function to sign out the user
     export const logout = () => {
       return auth.signOut();
     };
    

These functions will allow users to sign in using either email/password or their Google account, keeping their food orders tied to their account.

** Want to get honest opinions or like the way I write? Have a gig for me?
Drop me a mail:
**


Step 6: Login Component with Real-Life Example

Let’s say a user, Emma, wants to sign in to her Note Taking App account to track her recent notes. We’ll create a Login component that lets her sign in using email/password or her Google account.

  1. Create index.js inside src/components/auth/login/:

    ```javascript import React, { useState } from 'react' import { doSignInWithEmailandPassword,doSignInWithGoogle } from '../../../firebase/auth'; import { useAuth } from '../../../contexts/authContexts'; import { Navigate, Link } from 'react-router-dom';

    export default function Login() { const{userLoggedIn} = useAuth()

    const [email,setEmail] = useState(''); const [password,setPassword] = useState(''); const [isSigningIn,setIsSigningIn] = useState(false); const [errorMessage,setErrorMessage] = useState('');

    const onSubmit = async(e)=>{ e.preventDefault() if(!isSigningIn){ setIsSigningIn(true); await doSignInWithEmailandPassword(email,password) } }

    const onGoogleSignIn = async(e)=>{ e.preventDefault() if(!isSigningIn){ setIsSigningIn(true); doSignInWithGoogle().catch(err=>{ setIsSigningIn(false) }) } } return (

    {userLoggedIn && ()}

    Welcome Back

    Email { setEmail(e.target.value) }} className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg transition duration-300" />
Password { setPassword(e.target.value) }} className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg transition duration-300" />

{errorMessage && ( {errorMessage} )}

{isSigningIn ? 'Signing In...' : 'Sign In'}

Don't have an account? Sign up

OR
{ onGoogleSignIn(e) }} className={w-full flex items-center justify-center gap-x-3 py-2.5 border rounded-lg text-sm font-medium ${isSigningIn ? 'cursor-not-allowed' : 'hover:bg-gray-100 transition duration-300 active:bg-gray-100'}}> {isSigningIn ? 'Signing In...' : 'Continue with Google'}

) }



Emma can now log into her account, whether through her email/password or Google, and view her order status instantly!

---

### Step 7: Register Component

Now, let's add a **Register** component for new user who want to sign up for the app, like Emma’s friend John, who’s trying to write his first note.

1. **Create** `index.js` inside `src/components/auth/register/`:

    ```javascript
    import React,{useState} from 'react'
    import { Navigate, Link, useNavigate } from 'react-router-dom'
    import { useAuth } from '../../../contexts/authContexts'
    import { doCreateUserWithEmailandPassword } from '../../../firebase/auth'

    export default function Register() {
      const navigate = useNavigate()

      const [email, setEmail] = useState('')
      const [password, setPassword] = useState('')
      const [confirmPassword, setconfirmPassword] = useState('')
      const [isRegistering, setIsRegistering] = useState(false)
      const [errorMessage, setErrorMessage] = useState('')

      const { userLoggedIn } = useAuth()

      const onSubmit = async (e) => {
          e.preventDefault()
          if(!isRegistering) {
              setIsRegistering(true)
              await doCreateUserWithEmailandPassword(email, password)
          }
      }
      return (
        <div>
          {userLoggedIn && (<Navigate to={'/home'} replace={true} />)}

    <main className="w-full h-screen flex self-center place-content-center place-items-center">
        <div className="w-96 bg-white text-gray-600 space-y-5 p-4 shadow-xl border rounded-xl">
            <div className="text-center mb-6">
                <div className="mt-2">
                    <h3 className="text-gray-800 text-xl font-semibold sm:text-2xl">Create a New Account</h3>
                </div>

            </div>
            <form onSubmit={onSubmit} className="space-y-4">
                <div>
                    <label className="text-sm text-gray-600 font-bold">
                        Email
                    </label>
                    <input
                        type="email"
                        autoComplete='email'
                        required
                        value={email} onChange={(e) => { setEmail(e.target.value) }}
                        className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:indigo-600 shadow-sm rounded-lg transition duration-300"
                    />
                </div>
                <div>
                    <label className="text-sm text-gray-600 font-bold">
                        Password
                    </label>
                    <input
                        disabled={isRegistering}
                        type="password"
                        autoComplete='new-password'
                        required
                        value={password} onChange={(e) => { setPassword(e.target.value) }}
                        className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg transition duration-300"
                    />
                </div>
                <div>
                    <label className="text-sm text-gray-600 font-bold">
                        Confirm Password
                    </label>
                    <input
                        disabled={isRegistering}
                        type="password"
                        autoComplete='off'
                        required
                        value={confirmPassword} onChange={(e) => { setconfirmPassword(e.target.value) }}
                        className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg transition duration-300"
                    />
                </div>

                {errorMessage && (
                    <span className='text-red-600 font-bold'>{errorMessage}</span>
                )}

                <button
                    type="submit"
                    disabled={isRegistering}
                    className={`w-full px-4 py-2 text-white font-medium rounded-lg ${isRegistering ? 'bg-gray-300 cursor-not-allowed' : 'bg-indigo-600 hover:bg-indigo-700 hover:shadow-xl transition duration-300'}`}
                >
                    {isRegistering ? 'Signing Up...' : 'Sign Up'}
                </button>
                <div className="text-sm text-center">
                    Already have an account? {'   '}
                    <Link to={'/login'} className="text-center text-sm hover:underline font-bold">Continue</Link>
                </div>
            </form>
        </div>
    </main>
        </div>
      )
    }

With this component, John can quickly create an account, order his meal, and start tracking it right away.


Step 8: Header Component

You'll need to call this actions in header. Set up an index.js file inside src/header folder:

import React from 'react'
import { Link, useNavigate } from 'react-router-dom';
import { useAuth } from '../../contexts/authContexts';
import { doSignOut } from '../../firebase/auth';

const Header = () => {
    const navigate = useNavigate()
    const { userLoggedIn } = useAuth()
    return (
        <nav className='flex backdrop-blur-xl flex-row gap-x-2 w-full z-20 fixed top-0 left-0 h-12 border-b place-content-center items-center'>
            {
                userLoggedIn
                    ?
                    <>
                        <button onClick={() => { doSignOut().then(() => { navigate('/login') }) }} className='text-md text-white font-semibold underline'>Logout</button>
                    </>
                    :
                    <>
                        <Link className='text-md text-white font-semibold underline' to={'/login'}>Login</Link>
                        <Link className='text-md text-white font-semibold underline' to={'/register'}>Register New Account</Link>
                    </>
            }

        </nav>
    )
}

export default Header

This way, now you can add this component in your main app file for routing and Voila! Your Authentication is done.
Try out and experiment with your own project and drop me a comment if this sounds helpful and interesting!

Stay tuned for chapter 2 called "Storing the data in MongoDB"!

Find me on this socials. I would love to connect with you:

Have a wonderful day🌻!