Gatsby Firebase Authentication

Fri Oct 08 2021

In this tutorial we will integrate Firebase authentication in Gatsby project. We will use gatsby-plugin-firebase to integrate firebase with our Gatsby project.

NOTE: If you are following along this tutorial make sure to install firebase version 7.24.0 or any version prior to version 9 as firebase version 9 has breaking changes, so this tutorial will not work with version 9

Create a gatsby project. Open terminal and type

gatsby new project-name

Once its done, move into project directory and install firebase, gatsby-plugin-firebase and dotenv packages.

npm install firebase gatsby-plugin-firebase dotenv

Open the project in code editor. Goto gatsby-config file and at the top we will bring dotenv package we just installed.

require("dotenv").config()

inside plugins array configure gatsby-plugin-firebase.

{
    resolve: "gatsby-plugin-firebase",
    options: {
    credentials: {
        apiKey: process.env.API_KEY,
        authDomain: process.env.AUTH_DOMAIN,
        databaseURL: process.env.DATABASE_URL,
        projectId: process.env.PROJECT_ID,
        storageBucket: process.env.STORAGE_BUCKET,
        messagingSenderId: process.env.MESSAGING_SENDER_ID,
        appId: process.env.APP_ID,
        },
    },
},

make sure you have created a .env file at root level of project and add values the above mentioned environment variables there as well as their values from your firebase project.

Now goto gatsby-browser.js file and import firebase auth

import 'firebase/auth'

Create 2 files in pages directory, register.js and login.js and a form with 2 input fields for email and password and a button to submit the form

Now in src directory create a folder context and inside it create a file auth.js and paste the following code

import React, { createContext, useState, useEffect } from "react"
import firebase from "gatsby-plugin-firebase"

export const AuthContext = createContext({})

const AuthProvider = ({ children }) => {
  const [user, setUser] = useState()
  
  useEffect(() => {
	firebase.auth().onAuthStateChanged(user => setUser(user))  	
  }, [])
  
  return <AuthContext.Provider value={{ user, setUser }}>{children}</AuthContext.Provider>
}

export default AuthProvider

here we have created Auth Provider. When the app mounts we are listening for auth state changed and if there is a logged in user then we are setting that user into state and we have passed user and setUser as value to the AuthContext.Provider to access these values in our app.

Goto gatsby-browser.js file and paste the following code after firebase auth import

import React from "react"
import AuthProvider from "./src/context/auth"

export const wrapRootElement = ({ element }) => (
  <AuthProvider>{element}</AuthProvider>
)

Here we have wrapped our app with AuthProvider

Goto pages/register.js and import useState and useContext from react and initialize state for email and password fields, bind the values to input fields and add an onChange function to email and password fields also attach an onSubmit function to form itself. We will also import AuthContext from context/auth.js file so register.js will look something like this

import React, { useState, useContext } from "react"
import { navigate } from "gatsby"
import { AuthContext } from "../context/auth"

const Register = () => {
  const [data, setData] = useState({
    email: "",
    password: "",
  })
  
  const { setUser } = useContext(AuthContext)

  const handleChange = e =>
    setData({ ...data, [e.target.name]: e.target.value })

  const handleSubmit = async e => {
    e.preventDefault()
  }
  return (
    <form onSubmit={handleSubmit}>
      <h4>Create an account</h4>
      <div>
        <label htmlFor="email">Email</label>
        <input
          type="email"
          name="email"
          value={data.email}
          onChange={handleChange}
        />
      </div>
      <div>
        <label htmlFor="password">Password</label>
        <input
          type="password"
          name="password"
          value={data.password}
          onChange={handleChange}
        />
      </div>
      <div>
        <button>Register</button>
      </div>
    </form>
  )
}

export default Register

now at the top import firebase

import firebase from "gatsby-plugin-firebase"

and replace the existing handleSubmit function with this

const handleSubmit = async e => {
    e.preventDefault()
    try {
      const result = await firebase
        .auth()
        .createUserWithEmailAndPassword(data.email, data.password)
      setUser(result.user)
      navigate("/")
    } catch (err) {
      console.log(err.message)
    }
  }

Here we have used createUserWithEmailAndPassword method and passed email and password as arguments. Once the user is created, we have set the user in our global state which we also brought from our context file and finally redirecting the user to home page.

Copy this code and paste into login.js. Rename Register function to Login and change heading. There is one more change. In handleSubmit function replace createUserWithEmailAndPassword with signInWithEmailAndPassword and everything else will be same.

Now in components directory create file header.js if it is already not there.

More importantly, if you have layout.js file in components directory and you have wrapped register.js and login.js with layout then make sure to import header.js into layout.js if it is not already there otherwise you will have to import header.js into every file such as register.js, login.js, index.js as this explanation only focuses on functionalities and not layout / styling.

header.js will look something like this.

import React, { useContext } from "react"
import { Link, navigate } from "gatsby"
import { AuthContext } from "../context/auth"
import firebase from "gatsby-plugin-firebase"

const Header = () => {
  const { user } = useContext(AuthContext)

  const handleLogout = async () => {
    await firebase.auth().signOut()
    navigate("/login")
  }

  return (
    <div>
      <div>
        <Link to="/">Firebase Auth</Link>
      </div>
      <div>
        {!user ? (
          <>
            <Link to="/register">Register</Link>
            <Link to="/login">Login</Link>
          </>
        ) : (
          <button onClick={handleLogout}>Logout</button>
        )}
      </div>
    </div>
  )
}

export default Header

Here we are checking if user is logged in then we will show option to Logout otherwise user will see options to Register and Login and upon click on Logout button we will call firebase signOut method and navigate the user to login page.

Give it a try now. Run your gatsby app npm run develop and test the register, login and logout functionalities.

Share

Privacy Policy
icon
icon
icon
icon

Developed By Farhan Farooq