React app authentication using Firebase.

React app authentication using Firebase.

Photo by Jason Wong on Unsplash

Authentication is the most important part of any web app and creating your own authentication can be a tedious process, where we need to ensure proper security protection.

In this tutorial, we are going to implement authentication in react using firebase.

image.png

  • Click on Create a project

image.png

  • Enter the project name and check the terms and click on continue, In step 2 click on Continue.

image.png

  • On Step 3, check the Google Analytics terms and click on Create Project.

image.png

image.png

  • On the left pane of project categories, click on Build, then on Authentication, click on get started.

image.png

  • Now we need to enable the Sign-in methods, here we are going to enable Email and Google login.

image.png

  • For Google login, enter the project public-facing name and a support email and click on save.

image.png

  • The Authentication Sign-in Method should look like this.

image.png

  • Now click on Project Overview on the left navigation panel.

image.png

  • We need to create the web app SDK for using firebase on our react app, so we need to click on the web app icon (</>).

  • A new window will open up to name the web app and click on register.

image.png

  • Copy the SDK to a notepad, we will use this later on our react app. image.png

  • Click on continue to console. we have completed the firebase setup and will move on to the react app.

  • Create a react app using npx in your local environment(vs code)

npx create-react-app learning-auth

Alternatively, you can use a sandbox like stackblitz.com to create a react-app. Here, we are using stackblitz, click on the react javascript to create a react app

image.png

Now install the dependencies - firebase, and react-router-dom.

image.png

For the local setup, use

npm install firebase
npm install react-router-dom

Now we need to set up the firebase details on our react app. Create a file at root naming as FirebaseConfig.js and enter the following code. This file will contain the details of your firebase SDK. Alternatively, these values should be put in the .env file to ensure security.

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

const config = {
  apiKey: 'AIzaSyBRC-iTooiHv6BM3yaUqSSWZTz6o',
  authDomain: 'learning-auth-ed6.firebaseapp.com',
  projectId: 'learning-auth-ed6',
  storageBucket: 'learning-auth-e6.appspot.com',
  messagingSenderId: '2031607',
  appId: '1:203111280607:web:2da097782c26de6a',
  measurementId: 'G-XH92FQ',
};

const firebaseApp = initializeApp(config);
const auth = getAuth(firebaseApp);

const firebaseConfig = {
  auth,
};

export default firebaseConfig;
  • Replace the config object key values with the values of your web app.

  • Now create a file at the root naming as FirebaseAuthService.js and paste in the following code. This file will contain the helper functions like register, login, etc.

import firebase from './FirebaseConfig';
import {
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  sendPasswordResetEmail,
  signInWithPopup,
  GoogleAuthProvider,
  onAuthStateChanged,
} from 'firebase/auth';

const auth = firebase.auth;

const registerUser = (email, password) => {
  return createUserWithEmailAndPassword(auth, email, password);
};

const loginUser = (email, password) => {
  return signInWithEmailAndPassword(auth, email, password);
};

const logoutUser = () => {
  return auth.signOut();
};

const loginWithGoogle = () => {
  const provider = new GoogleAuthProvider();

  return signInWithPopup(auth, provider);
};

const subscribeToAuthChanges = (handleAuthChange) => {
  onAuthStateChanged(auth, (user) => {
    handleAuthChange(user);
  });
};

const FirebaseAuthService = {
  registerUser,
  loginUser,
  logoutUser,
  sendPasswordResetEmail: (email) => {
    sendPasswordResetEmail(auth, email);
  },
  loginWithGoogle,
  subscribeToAuthChanges,
};

export default FirebaseAuthService;

Note:- Here all the functions return a promise except the logoutUser().

  • We have completed the firebase authentication setup on our react-app, now we need to create the components.

  • Create a folder at root naming it as pages and create five files naming them as Home.js, Register.js, Login.js, ForgotPassword.js, and index.js inside it.

  • We also need to create a context that will share the user and user details across multiple components.

  • So create a folder at root naming it as context and create a file inside it naming as auth-context.js and put in the following code.

import React, { createContext, useContext, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

const authContext = createContext();
const useAuth = () => useContext(authContext);

const AuthContextProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const navigate = useNavigate();

  useEffect(() => {
    if (!user) {
      navigate('/login');
    } else {
      navigate('/');
    }
  }, [user]);
  return (
    <authContext.Provider value={{ user, setUser }}>
      {children}
    </authContext.Provider>
  );
};

export { AuthContextProvider, useAuth };

Here we are creating an auth context where if the user is not logged in then using the useNavigate hook login page will be redirected else the homepage will be shown.

  • Now we can add the code for our components.

  • Add the following code to Home.js. In this file, if a user is logged in then a button will be shown to log out.

import React from 'react';
import FirebaseAuthService from '../FirebaseAuthService';
import { useAuth } from '../context/authContext';

function Home() {
  const { user, setUser } = useAuth();
  FirebaseAuthService.subscribeToAuthChanges(setUser);
  return (
    <div className="container">
      <h2>You have Successfully logged In</h2>
      <button
        className="button"
        onClick={() => FirebaseAuthService.logoutUser()}
      >
        Logout
      </button>
    </div>
  );
}

export { Home };
  • Add the following code to Login.js
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import FirebaseAuthService from '../FirebaseAuthService';
import { useAuth } from '../context/authContext';

function Login() {
  const [credentials, setCredentials] = useState({ email: '', password: '' });
  const { user, setUser } = useAuth();

  async function handleSubmit(e) {
    e.preventDefault();
    try {
      await FirebaseAuthService.loginUser(
        credentials.email,
        credentials.password
      );
      setCredentials({ email: '', password: '' });
      FirebaseAuthService.subscribeToAuthChanges(setUser);
      alert('Successfully Logged In');
    } catch (error) {
      alert(error.message);
    }
  }

  function changeHandler(e) {
    setCredentials({ ...credentials, [e.target.name]: e.target.value });
  }

  async function loginWithGoogle() {
    try {
      await FirebaseAuthService.loginWithGoogle();
    } catch (error) {
      alert(error.message);
    }
  }
  return (
    <div className="container">
      <h2>Login</h2>
      <form onSubmit={handleSubmit} className="form">
        <input
          type="email"
          placeholder="enter email"
          name="email"
          onChange={changeHandler}
          value={credentials.email}
          className="input-field"
        />
        <input
          type="password"
          placeholder="enter password"
          name="password"
          onChange={changeHandler}
          value={credentials.password}
          className="input-field"
        />
        <Link to="/reset">Forgot Password?</Link>
        <button type="submit" className="button">
          Login
        </button>
        <button type="button" className="button" onClick={loginWithGoogle}>
          Login Using Google
        </button>
        <Link to="/register">Create an account? Sign up</Link>
      </form>
    </div>
  );
}

export { Login };

Add the following code to Register.js

import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import FirebaseAuthService from '../FirebaseAuthService';
import { useAuth } from '../context/authContext';

function Register() {
  const [credentials, setCredentials] = useState({ email: '', password: '' });
  const { user, setUser } = useAuth();
  async function handleSubmit(e) {
    e.preventDefault();
    try {
      await FirebaseAuthService.registerUser(
        credentials.email,
        credentials.password
      );
      setCredentials({ email: '', password: '' });
      FirebaseAuthService.subscribeToAuthChanges(setUser);
      alert('Successfully signed up');
    } catch (error) {
      alert(error.message);
    }
  }

  function changeHandler(e) {
    setCredentials({ ...credentials, [e.target.name]: e.target.value });
  }
  return (
    <div className="container">
      <h2>Register</h2>
      <form onSubmit={handleSubmit} className="form">
        <input
          type="email"
          placeholder="enter email"
          name="email"
          onChange={changeHandler}
          value={credentials.email}
          className="input-field"
        />
        <input
          type="password"
          placeholder="enter password"
          name="password"
          onChange={changeHandler}
          value={credentials.password}
          className="input-field"
        />
        <button type="submit" className="button">
          Register
        </button>
        <Link to="/login">Already Having an Account? Login</Link>
      </form>
    </div>
  );
}

export { Register };

Add the following code to ForgotPassword.js

import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import FirebaseAuthService from '../FirebaseAuthService';

function ForgotPassword() {
  const [email, setEmail] = useState('');

  async function handleSubmit(e) {
    e.preventDefault();
    try {
      await FirebaseAuthService.sendPasswordResetEmail(email);
      setEmail('');
      alert('Successfully Sent Reset Password Link');
    } catch (error) {
      alert(error.message);
    }
  }

  return (
    <div className="container">
      <h2>Enter your Email to reset Password</h2>
      <form onSubmit={handleSubmit} className="form">
        <input
          type="email"
          placeholder="enter email"
          name="email"
          onChange={(e) => setEmail(e.target.value)}
          value={email}
          className="input-field"
        />

        <button type="submit" className="button">
          Reset Password
        </button>

        <Link to="/login">Login to your account? Sign in</Link>
      </form>
    </div>
  );
}

export { ForgotPassword };

And finally add the following code to index.js

export * from './Login';
export * from './Register';
export * from './Home';
export * from './ForgotPassword';

Here, in this file, we are exporting all the components.

  • Now we to add the contexts to the index.js file at the root.
import React, { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { AuthContextProvider } from './context/authContext';
import App from './App';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <BrowserRouter>
      <AuthContextProvider>
        <App />
      </AuthContextProvider>
    </BrowserRouter>
  </StrictMode>
);

Now, we just need to configure our routing for the components, so add the following code to App.js.

import React from 'react';
import { Routes, Route } from 'react-router-dom';
import './style.css';
import { Home, Login, Register, ForgotPassword } from './pages';
export default function App() {
  return (
    <div>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/register" element={<Register />} />
        <Route path="/login" element={<Login />} />
        <Route path="/reset" element={<ForgotPassword />} />
      </Routes>
    </div>
  );
}

Preview

chrome_z1wIUEw8bt.gif

Login using Google

DMPr4pI4ls.gif

You can find the source code of the app at github.com/Rohitprasad83/learning-auth

Resource used - firebase.google.com/docs/auth