Gatsby Firebase Authentication
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.