Digital AgencyRecord LabeleCommerceB2B Marketplace
PortfolioBlogContact

Best way to add authentication and database capabilities to a gatsby website

November 16, 2020

You have an existing gatsby website. You've built content pages and now you want to add more advanced functionality, like authentication to personalise experience and a database to store data for returning users. Here's a few simple steps to add authentication and database capabilities to your gatsby website. For ease of use this guide uses Firebase, there's other tools but it's really simple with Firebase.

Install packages

firebase: JavaScript library for web and Node.js.
gatsby-plugin-firebase: Enables gatsby drop-in support for Firebase.
react-firebaseui: Provides UI flows for authenticating with Firebase.
@reach/router: Reach Router is a small, simple router for React.
gatsby-plugin-create-client-paths: Helps create client paths private routes.

npm install firebase gatsby-plugin-firebase react-firebaseui @reach/router gatsby-plugin-create-client-paths --save

gatsby-browser.js

import "firebase/auth"
import "firebase/database"

gatsby-ssr.js

import "firebase/auth"
import "firebase/database"

gatsby-config.js

module.exports = {
  plugins: [
    ...otherPlugins,
    {
      resolve: "gatsby-plugin-firebase",
      options: {
        credentials: {
          apiKey: "<YOUR_FIREBASE_API_KEY>",
          authDomain: "<YOUR_FIREBASE_AUTH_DOMAIN>",
          databaseURL: "<YOUR_FIREBASE_DATABASE_URL>",
          projectId: "<YOUR_FIREBASE_PROJECT_ID>",
          storageBucket: "<YOUR_FIREBASE_STORAGE_BUCKET>",
          messagingSenderId: "<YOUR_FIREBASE_MESSAGING_SENDER_ID>",
          appId: "<YOUR_FIREBASE_APP_ID>"
        }
      }
    }
    {
      resolve: `gatsby-plugin-create-client-paths`,
      options: { prefixes: [`/app/*`] },
    },
  ],
}

login.js

import React from "react"
import { navigate } from "@reach/router";
import StyledFirebaseAuth from "react-firebaseui/StyledFirebaseAuth";
import firebase from "gatsby-plugin-firebase";
import { setUser, isLoggedIn } from "../utils/auth";
import SEO from "./seo";

export default ({ location }) => {
  if (isLoggedIn()) {
    if (location && location.state && location.state.redirect) {
      navigate(location.state.redirect);
    } else {
      navigate(`/`);
    }
  }

  const getUiConfig = (auth) => {
    return {
      signInFlow: "popup",
      signInOptions: [{ provider: firebase.auth.FacebookAuthProvider.PROVIDER_ID }, auth.GoogleAuthProvider.PROVIDER_ID, { provider: auth.EmailAuthProvider.PROVIDER_ID, requireDisplayName: false }],
      callbacks: {
        signInSuccessWithAuthResult: (result) => {
          setUser(result.user);
          if (location && location.state && location.state.redirect) {
            navigate(location.state.redirect);
          } else {
            navigate(`/`);
          }
        },
      },
    };
  }

  return (
    <div>
      <SEO title="Login" />
      <div>
        <p>Please Sign In</p>
        {firebase && <StyledFirebaseAuth uiConfig={getUiConfig(firebase.auth)} firebaseAuth={firebase.auth()} />}
      </div>
    </div>
  );
};

app.js

import React from "react"
import { Router } from "@reach/router"
import Layout from "../components/layout"
import SEO from "../components/seo"

import PrivateComponent from "../components/privateComponent"
import PrivateRoute from "../components/privateRoute"
import Login from "../components/login"

export default() => {
  return (
    <Layout>
      <SEO title="App" />
      <Router basepath="/app">
        <PrivateRoute path="/private" component={PrivateComponent} />
        <Login path="/login" />
      </Router>
    </Layout>
  );
};

utils auth.js

export const isBrowser = () => typeof window !== "undefined"
export const getUser = () => (isBrowser() && window.localStorage.getItem("user") ? JSON.parse(window.localStorage.getItem("user")) : {})
export const setUser = (user) => isBrowser() && window.localStorage.setItem("user", JSON.stringify(user))

export const isLoggedIn = () => {
  const user = getUser()
  return !!user.email
}

export const logout = (firebase) => {
  return new Promise((resolve) => {
    firebase
      .auth()
      .signOut()
      .then(function () {
        setUser({})
        resolve()
      })
  })
}

privateRoute.js

import React from "react"
import { navigate } from "gatsby"
import { isLoggedIn } from "../utils/auth"

export default ({ component: Component, location, ...rest }) => {
  if (!isLoggedIn() && location.pathname !== `/app/login`) {
    navigate(`/app/login`, {state: { redirect: rest.uri } });
    return null;
  }
  return <Component {...rest} />;
};

© Digital Central, 2020 - All Rights Reserved.