Firebase Authentication in React: A Simple Step-by-Step Guide

Firebase Authentication in React: A Simple Step-by-Step Guide Authentication is a fundamental requirement for most web applications. In this tutorial, I'll walk you through implementing Firebase Authentication in a React application without using the Context API. We'll create sign-up and sign-in pages and set up navigation to a home page after successful authentication. What We'll Build A React application with Firebase Authentication Sign-up page for new users Sign-in page for existing users Protected home page that requires authentication Simple navigation between these pages Prerequisites Basic knowledge of React Node.js and npm installed on your computer A Google account to set up Firebase Step 1: Set Up a New React Project Let's start by creating a new React application: npx create-react-app firebase-auth-app cd firebase-auth-app Step 2: Install Required Dependencies We'll need to install Firebase and React Router: npm install firebase react-router-dom Step 3: Create a Firebase Project Go to the Firebase Console Click "Add project" and follow the setup instructions Once your project is created, click on the web icon () to add a web app to your project Register your app with a nickname (e.g., "firebase-auth-app") Copy the Firebase configuration object that looks like this: const firebaseConfig = { apiKey: "your-api-key", authDomain: "your-project-id.firebaseapp.com", projectId: "your-project-id", storageBucket: "your-project-id.appspot.com", messagingSenderId: "your-messaging-sender-id", appId: "your-app-id" }; Step 4: Enable Authentication Methods in Firebase In the Firebase Console, navigate to "Authentication" in the left sidebar Click on "Get started" Enable "Email/Password" authentication by clicking on it and toggling the switch to "Enable" Click "Save" Step 5: Set Up Firebase in Your React App Create a new file src/firebase.js to initialize Firebase: // src/firebase.js import { initializeApp } from 'firebase/app'; import { getAuth } from 'firebase/auth'; const firebaseConfig = { // Replace with your Firebase config object apiKey: "your-api-key", authDomain: "your-project-id.firebaseapp.com", projectId: "your-project-id", storageBucket: "your-project-id.appspot.com", messagingSenderId: "your-messaging-sender-id", appId: "your-app-id" }; // Initialize Firebase const app = initializeApp(firebaseConfig); export const auth = getAuth(app); export default app; Step 6: Create the Sign-Up Component // src/components/Signup.js import React, { useState } from 'react'; import { createUserWithEmailAndPassword } from 'firebase/auth'; import { auth } from '../firebase'; import { Link, useNavigate } from 'react-router-dom'; function Signup() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const navigate = useNavigate(); async function handleSubmit(e) { e.preventDefault(); if (password !== confirmPassword) { return setError('Passwords do not match'); } try { setError(''); setLoading(true); await createUserWithEmailAndPassword(auth, email, password); navigate('/'); } catch (error) { setError('Failed to create an account: ' + error.message); } setLoading(false); } return ( Sign Up {error && {error}} Email setEmail(e.target.value)} required /> Password setPassword(e.target.value)} required /> Confirm Password setConfirmPassword(e.target.value)} required /> Sign Up Already have an account? Log In ); } export default Signup; Step 7: Create the Login Component // src/components/Login.js import React, { useState } from 'react'; import { signInWithEmailAndPassword } from 'firebase/auth'; import { auth } from '../firebase'; import { Link, useNavigate } from 'react-router-dom'; function Login() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const navigate = useNavigate(); async function handleSubmit(e) { e.preventDefault(); try { setError(''); setLoading(true); await signInWithEmailAndPassword(auth, email, password); navigate('/'); } catch (error) { setError('Failed to log in: ' + error.message); } setLoading(false); } return (

May 17, 2025 - 21:26
 0
Firebase Authentication in React: A Simple Step-by-Step Guide

Firebase Authentication in React: A Simple Step-by-Step Guide

Authentication is a fundamental requirement for most web applications. In this tutorial, I'll walk you through implementing Firebase Authentication in a React application without using the Context API. We'll create sign-up and sign-in pages and set up navigation to a home page after successful authentication.

What We'll Build

  • A React application with Firebase Authentication
  • Sign-up page for new users
  • Sign-in page for existing users
  • Protected home page that requires authentication
  • Simple navigation between these pages

Prerequisites

  • Basic knowledge of React
  • Node.js and npm installed on your computer
  • A Google account to set up Firebase

Step 1: Set Up a New React Project

Let's start by creating a new React application:

npx create-react-app firebase-auth-app
cd firebase-auth-app

Step 2: Install Required Dependencies

We'll need to install Firebase and React Router:

npm install firebase react-router-dom

Step 3: Create a Firebase Project

  1. Go to the Firebase Console
  2. Click "Add project" and follow the setup instructions
  3. Once your project is created, click on the web icon () to add a web app to your project
  4. Register your app with a nickname (e.g., "firebase-auth-app")
  5. Copy the Firebase configuration object that looks like this:
const firebaseConfig = {
  apiKey: "your-api-key",
  authDomain: "your-project-id.firebaseapp.com",
  projectId: "your-project-id",
  storageBucket: "your-project-id.appspot.com",
  messagingSenderId: "your-messaging-sender-id",
  appId: "your-app-id"
};

Step 4: Enable Authentication Methods in Firebase

  1. In the Firebase Console, navigate to "Authentication" in the left sidebar
  2. Click on "Get started"
  3. Enable "Email/Password" authentication by clicking on it and toggling the switch to "Enable"
  4. Click "Save"

Step 5: Set Up Firebase in Your React App

Create a new file src/firebase.js to initialize Firebase:

// src/firebase.js
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';

const firebaseConfig = {
  // Replace with your Firebase config object
  apiKey: "your-api-key",
  authDomain: "your-project-id.firebaseapp.com",
  projectId: "your-project-id",
  storageBucket: "your-project-id.appspot.com",
  messagingSenderId: "your-messaging-sender-id",
  appId: "your-app-id"
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export default app;

Step 6: Create the Sign-Up Component

// src/components/Signup.js
import React, { useState } from 'react';
import { createUserWithEmailAndPassword } from 'firebase/auth';
import { auth } from '../firebase';
import { Link, useNavigate } from 'react-router-dom';

function Signup() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);
  const navigate = useNavigate();

  async function handleSubmit(e) {
    e.preventDefault();

    if (password !== confirmPassword) {
      return setError('Passwords do not match');
    }

    try {
      setError('');
      setLoading(true);
      await createUserWithEmailAndPassword(auth, email, password);
      navigate('/');
    } catch (error) {
      setError('Failed to create an account: ' + error.message);
    }

    setLoading(false);
  }

  return (
    <div className="signup-container">
      <div className="signup-form">
        <h2>Sign Up</h2>
        {error && <div className="error-message">{error}</div>}
        <form onSubmit={handleSubmit}>
          <div className="form-group">
            <label>Email</label>
            <input
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              required
            />
          </div>
          <div className="form-group">
            <label>Password</label>
            <input
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
            />
          </div>
          <div className="form-group">
            <label>Confirm Password</label>
            <input
              type="password"
              value={confirmPassword}
              onChange={(e) => setConfirmPassword(e.target.value)}
              required
            />
          </div>
          <button disabled={loading} type="submit" className="submit-button">
            Sign Up
          </button>
        </form>
        <div className="login-link">
          Already have an account? <Link to="/login">Log In</Link>
        </div>
      </div>
    </div>
  );
}

export default Signup;

Step 7: Create the Login Component

// src/components/Login.js
import React, { useState } from 'react';
import { signInWithEmailAndPassword } from 'firebase/auth';
import { auth } from '../firebase';
import { Link, useNavigate } from 'react-router-dom';

function Login() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);
  const navigate = useNavigate();

  async function handleSubmit(e) {
    e.preventDefault();

    try {
      setError('');
      setLoading(true);
      await signInWithEmailAndPassword(auth, email, password);
      navigate('/');
    } catch (error) {
      setError('Failed to log in: ' + error.message);
    }

    setLoading(false);
  }

  return (
    <div className="login-container">
      <div className="login-form">
        <h2>Log In</h2>
        {error && <div className="error-message">{error}</div>}
        <form onSubmit={handleSubmit}>
          <div className="form-group">
            <label>Email</label>
            <input
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              required
            />
          </div>
          <div className="form-group">
            <label>Password</label>
            <input
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
            />
          </div>
          <button disabled={loading} type="submit" className="submit-button">
            Log In
          </button>
        </form>
        <div className="signup-link">
          Need an account? <Link to="/signup">Sign Up</Link>
        </div>
      </div>
    </div>
  );
}

export default Login;

Step 8: Create the Home Component

// src/components/Home.js
import React, { useState, useEffect } from 'react';
import { onAuthStateChanged, signOut } from 'firebase/auth';
import { auth } from '../firebase';
import { useNavigate } from 'react-router-dom';

function Home() {
  const [currentUser, setCurrentUser] = useState(null);
  const navigate = useNavigate();

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      if (user) {
        setCurrentUser(user);
      } else {
        navigate('/login');
      }
    });

    return () => unsubscribe();
  }, [navigate]);

  async function handleLogout() {
    try {
      await signOut(auth);
      navigate('/login');
    } catch (error) {
      console.error('Failed to log out:', error);
    }
  }

  if (!currentUser) return <div>Loading...</div>;

  return (
    <div className="home-container">
      <h2>Welcome to Your Dashboard!</h2>
      <p>You are logged in as: {currentUser.email}</p>
      <button onClick={handleLogout} className="logout-button">
        Log Out
      </button>
    </div>
  );
}

export default Home;

Step 9: Create a Simple Auth Check Component

Instead of using the Context API, we'll create a simple component to check if a user is authenticated:

// src/components/AuthCheck.js
import React, { useState, useEffect } from 'react';
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from '../firebase';
import { Navigate } from 'react-router-dom';

function AuthCheck({ children }) {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setIsAuthenticated(!!user);
      setIsLoading(false);
    });

    return () => unsubscribe();
  }, []);

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    return <Navigate to="/login" />;
  }

  return children;
}

export default AuthCheck;

Step 10: Set Up App Routing

Now, let's update the main App component to include all our routes:

// src/App.js
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import AuthCheck from './components/AuthCheck';
import Signup from './components/Signup';
import Login from './components/Login';
import Home from './components/Home';
import './App.css';

function App() {
  return (
    <Router>
      <div className="app-container">
        <Routes>
          <Route path="/" element={
            <AuthCheck>
              <Home />
            </AuthCheck>
          } />
          <Route path="/signup" element={<Signup />} />
          <Route path="/login" element={<Login />} />
        </Routes>
      </div>
    </Router>
  );
}

export default App;

Step 11: Add Basic CSS Styling

Let's add some minimal CSS to make our app look decent:

/* src/App.css */
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: Arial, sans-serif;
  background-color: #f4f4f4;
}

.app-container {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  padding: 20px;
}

.signup-container,
.login-container,
.home-container {
  background-color: white;
  border-radius: 5px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  padding: 20px;
  width: 100%;
  max-width: 400px;
}

h2 {
  text-align: center;
  margin-bottom: 20px;
}

.form-group {
  margin-bottom: 15px;
}

label {
  display: block;
  margin-bottom: 5px;
}

input {
  width: 100%;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 16px;
}

.submit-button,
.logout-button {
  width: 100%;
  padding: 10px;
  background-color: #4285f4;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 16px;
  cursor: pointer;
  margin-top: 10px;
}

.submit-button:hover,
.logout-button:hover {
  background-color: #357ae8;
}

.submit-button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.error-message {
  background-color: #ffebee;
  color: #c62828;
  padding: 10px;
  border-radius: 4px;
  margin-bottom: 15px;
  text-align: center;
}

.login-link,
.signup-link {
  text-align: center;
  margin-top: 15px;
}

.home-container p {
  margin-bottom: 20px;
}

Step 12: Run and Test Your Application

Now let's run the application and test our authentication flow:

npm start

Your React application should open in your default browser at http://localhost:3000.

Testing the Flow

Let's test our authentication flow to make sure everything works as expected:

  1. Sign-up flow:

    • Navigate to /signup
    • Create a new account with email and password
    • After successful registration, you should be redirected to the home page
  2. Login flow:

    • Log out from the home page
    • You should be redirected to the login page
    • Enter your credentials
    • After successful login, you should be redirected to the home page
  3. Authentication protection:

    • Try accessing the home page (/) directly when not logged in
    • You should be redirected to the login page

Understanding How It Works

Authentication Flow

  1. Firebase Setup: We initialize Firebase and its authentication service in firebase.js.

  2. Sign Up:

    • When a user submits the sign-up form, we call Firebase's createUserWithEmailAndPassword function
    • If successful, we navigate to the home page
    • If there's an error, we display it to the user
  3. Login:

    • When a user submits the login form, we call Firebase's signInWithEmailAndPassword function
    • If successful, we navigate to the home page
    • If there's an error, we display it to the user
  4. Authentication Check:

    • We use Firebase's onAuthStateChanged to listen for authentication state changes
    • In the AuthCheck component, we redirect unauthenticated users to the login page
    • In the Home component, we use this to get the current user's information
  5. Logout:

    • When a user clicks the logout button, we call Firebase's signOut function
    • After logging out, we redirect the user to the login page

Common Issues and Troubleshooting

Firebase Initialization Errors

If you see an error like "Firebase App named '[DEFAULT]' already exists", make sure you're only initializing Firebase once in your application.

Authentication Errors

  • Check that you've enabled Email/Password authentication in the Firebase Console
  • Make sure password meets Firebase's minimum requirements (at least 6 characters)
  • Verify that you're using the correct Firebase configuration

Routing Issues

  • Ensure all routes are properly defined in App.js
  • Verify that AuthCheck is correctly protecting your routes

Next Steps

Now that you have a basic authentication system in place, you might want to:

  1. Add password reset functionality
  2. Implement social media login options (Google, Facebook, etc.)
  3. Create a user profile page with more information
  4. Add email verification
  5. Implement more robust error handling

Conclusion

You've successfully built a React application with Firebase Authentication! You now have functional sign-up and sign-in pages that redirect users to a protected home page after successful authentication.

This implementation uses a straightforward approach without the Context API, making it easier to understand and maintain. You can build upon this foundation to create more complex applications with user authentication.

Happy coding!