
In this tutorial, we will create a real-world react application for user registration. we will use google’s firebase for registering the user and also use the concept of private routes(route guard) for allowing only registered users into the user profile section. For the user authentication, we will create a custom hook using react context & hooks concept.
1.Setup the project :
we are going to use create-react-app to bootstrap the project.
Run the below commands in the terminal to setup initial project:2.
# bootstrap a new react application
npx create-react-app react-firebase-authentication
# access the project
cd ./react-firebase-authentication
# start project in development mode
npm start
2.Setup the Firebase :
Start creating a Firebase project if you don’t have one already.
Go to authentication Page.Click on the sign-in method & select Email & password option.

Setup authorised Domain:
Scroll down below and check if the authorised domain is set to localhost by default.

Copy Firebase Configuration Keys:
Go to project settings and under the general tab, you can get all the required configuration keys. We need all these keys once we start working on our project.

3.Install depedancy in react Project:
There are a few dependencies we need to install before starting with our react authentication project.
Firstly we need to install firebase to our react application.
npm install firebase
This will take a minute/s to install the firebase.
Now install react-router for creating routes for the users.
npm install react-router-dom
Now finally install bootstrap & react bootstrap to use in our application.
npm install bootstrap react-bootstrap
4.Code:
Follow the below steps to understand the complete code for react registration authentication with firebase.
1.Create env.Local file:
Create a .env.local file in your project and the env variables as shown, now paste the configuration keys which were copied from google firebase.
REACT_APP_FIREBASE_API_KEY=
REACT_APP_FIREBASE_AUTH_DOMAIN=
REACT_APP_FIREBASE_PROJECT_ID=
REACT_APP_FIREBASE_STORAGE_BUCKET=
REACT_APP_FIREBASE_MESSAGE_SENDER_ID=
REACT_APP_FIREBASE_APP_ID=
2.Create firebase.js
Here we are initializing our firebase Application & create the authentication object which we will be using for registering the user.
import firebase from 'firebase/app';
import 'firebase/auth'
const app=firebase.initializeApp({
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGE_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID
});
export const auth = app.auth();
export default app;
3.create AuthContext.js
Here we are going to use ContextProvider we render every component inside ContextProvider as a child component. Context is basically used to access data anywhere inside the application without making use of props. We provide the values to ContextProvider, now they can be accessed anywhere using consumer or useContext.
We use useConext to get context which will return all values we pass to our context provider.
Here we have defined the signup method which will be used in the signup component. Inside this method, we will call the API to create the user in google’s firebase and return it to called function.
import React,{createContext,useContext,useState,useEffect} from 'react'
import { auth } from '../firebase'
const AuthContext = createContext();
export function useAuth(){
return useContext(AuthContext);
}
export function AuthProvider({ children }) {
const [user,setUser]=useState();
function SignUp(email,password){
return auth.createUserWithEmailAndPassword(email,password)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user =>{
setUser(user);
})
return unsubscribe
},[])
const value = {
user,
SignUp,
}
return (
<AuthContext.Provider value={value}>
{ children }
</AuthContext.Provider>
)
}
Note: Whenever any action is performed using auth object of firebase it will automatically call onAuthStateChanged method, hence we use it in useEffect and we return a function reference(unsubscribe) from useEffect to unsubscribe whenever component un-mounts.
4.create signup component:
We need to create a signup component. Let’s use Card, Form, Alert, Button from react-bootstrap, you can check the HTML part of the code .now let’s use emailref, passwordref & currentpasswordref to store the values entered by the user.
import React,{useRef,useState} from 'react';
import { Form,Button,Card,Alert } from 'react-bootstrap';
import { useAuth } from '../contexts/AuthContext';
import { Link,useHistory } from 'react-router-dom';
const emailRef=useRef();
const passwordRef=useRef()
const confirmPasswordRef=useRef();
const { SignUp, user} =useAuth();
const [error,setError] =useState('');
const [loading ,setLoading]=useState(false);
const history = useHistory();
useHistory is a hook from react-router-dom which can be used to update the URLs. We have used the error state variable for checking the error.
import React,{useRef,useState} from 'react';
import { Form,Button,Card,Alert } from 'react-bootstrap';
import { useAuth } from '../contexts/AuthContext';
import { Link,useHistory } from 'react-router-dom';
function Signup(){
const emailRef=useRef();
const passwordRef=useRef()
const confirmPasswordRef=useRef();
const { SignUp, user} =useAuth();
const [error,setError] =useState('');
const [loading ,setLoading]=useState(false);
const history = useHistory();
async function handleSubmit(e){
e.preventDefault();
if(passwordRef.current.value !== confirmPasswordRef.current.value)
{
return setError("password do not match");
}
try{
setError("");
setLoading(true);
await SignUp(emailRef.current.value,passwordRef.current.value)
history.push("/")
}catch(error){
setError(error.message);
}
setLoading(false);
}
return (
<React.Fragment>
<Card>
<Card.Body>
<h2 className="text-center mb-4">Sign Up</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control type="email" ref={emailRef} required/>
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control type="password" ref={passwordRef} required/>
</Form.Group>
<Form.Group id="confirm_password">
<Form.Label>Confirm Password</Form.Label>
<Form.Control type="password" ref={confirmPasswordRef} required/>
</Form.Group>
<Button disabled= {loading} className="w-100" type="submit">
Sign Up
</Button>
</Form>
</Card.Body>
</Card>
<div className="w-100 text-center mt-2">
Already have an Account? <Link to="/login">Log In</Link>
</div>
</React.Fragment>
);
}
export default Signup;
We have handlesubmit method to handle signup events generated by the user. in handlesubmit we call the signup function that we have created in authContext.js
If the registration is successful then we redirect to “/” i.e dashboard (we will see it later) else we set the error thrown by firebase to error object & display the message.
Here we are using loading state objects to prevent users from submitting multiple requests when our application is busy authenticating with firebase.
5.Update App.js:
In app.js we add react-router’s router, switch & routes for manual routing, we used AuthProvider which is a context Provider. We created protected routes so the authenticated users only get to the profile page.
You can refer to my previous post on the private route for this.Click Here
import Signup from './components/SignUp'
import Dashboard from './components/Dashboard'
import {Container} from 'react-bootstrap'
import { AuthProvider } from './contexts/AuthContext'
import { BrowserRouter as Router,Switch,Route} from 'react-router-dom'
import PrivateRoute from './components/PrivateRoute';
function App() {
return (
<Container className={ "d-flex align-items-center justify-content-center" } style={{minHeight:'100vh'}}>
<div className="w-100" style={{ maxWidth:'400px'}}>
<Router>
<AuthProvider>
<Switch>
<PrivateRoute exact path='/' component={Dashboard}/>
<Route path="/signup" component={Signup}/>
</Switch>
</AuthProvider>
</Router>
</div>
</Container>
);
}
export default App;
import React from 'react'
import {Route,Redirect} from 'react-router-dom'
import {useAuth} from '../contexts/AuthContext'
export default function PrivateRoute({component:Component,...rest}) {
const {user} =useAuth();
return (
<Route {...rest} render={
props=>{
return user ? <Component {...props}/>:<Redirect to='/login'/>
}
}>
</Route>
)
}