developers

Securing Gatsby with Auth0

Learn how to set up Auth0 for identity management in a Gatsby static site.

TL;DR: In this article, you'll learn how to secure a basic Gatsby static site with Auth0. The finished code for this tutorial is at the

gatsby-auth0-sample-app
repository.

Gatsby beautifully merges technologies like GraphQL and MDX with concepts like progressive web apps and server-side rendering. There's even an easy-to-use command line interface (the Gatsby CLI) to make developing, building, and deploying your static site virtually painless. To me, it is the most intuitive JAM stack (JavaScript + APIs + Markup) solution out there.

@GatsbyJS is a powerful static site generator combining React, GraphQL, and many other modern web technologies.

Tweet This

As wonderful as this is, many static sites still need authentication. Stores, member areas, or admin dashboards can all be built as static sites, and all require either a protected route or a persisted user profile. Luckily, Auth0 is here to help.

This article will take a slightly different path than our typical authentication tutorial. Ordinarily, I would have you build a sample application that includes styling and a source of data. Because Gatsby orchestrates things like GraphQL, CSS-in-JS, API data, and much more, it's incredibly easy to get lost in the weeds in a tutorial and lose track of what is specific to Gatsby.

For that reason, I'm going to have you build the absolute simplest (and, well, ugliest) sample application possible so you can focus solely on learning how to set up authentication in that app. I won't be covering any data sources, GraphQL, or styling strategies. Keeping this tutorial super-simple means that this strategy will work for you whether you're building a blog, a store, or anything else your heart desires.

Prerequisites

To go through this tutorial, you will need Node.js 16 and NPM installed. You should download and install them before continuing.

You'll also need some basic knowledge of React. You only need to know the basic scaffolding of components and JSX to follow along, but it will be difficult if you're a total beginner. If that's you, you can read our article on building and securing your first React app before continuing.

Gatsby Basics

To get started with Gatsby, you'll first need to install the Gatsby CLI globally on your machine. You can do that by running the command:

npm install -g gatsby-cli

The Gatsby CLI has some built-in commands like

develop
to run a development server,
build
to generate a production build, and
serve
to serve the production build. There are many other options and commands that you can check out in the Gatsby CLI docs.

One cool feature of the CLI is the ability to use a starter as the template for a new project. You can use either an official Gatsby starter or any other Gatsby repository. For this tutorial, you'll use

gatsby-starter-hello-world
by running the following command:

gatsby new gatsby-auth0 gatsbyjs/gatsby-starter-hello-world

Note that the first argument (

gatsby-auth0
) is just the name of the new project. You can call it whatever you'd like.

Gatsby will automatically run

npm install
for you, so once that's done, open the project in your preferred editor. You'll see the simplest possible Gatsby project, which includes one file inside of the
src/pages/
folder called
index.js
. Open that file and replace it with the following:

// ./src/pages/index.js
import React from "react";
import { Link } from "gatsby";

export default () => (
  <div>
   <p>Hello Gatsby!</p>
   <Link to="/account">Go to your account</Link>
 </div>
);

You can see that this is a super simple React component written in JSX. It imports Gatsby's

Link
function to navigate to an
account
route. You'll create that route in the next section. For now, run the command
gatsby develop
in your terminal and navigate to
localhost:8000
. You should see "Hello Gatsby!" with a link to go to the account page.

Create an Account Route

You've now created your first static site with Gatsby — congratulations! You're ready to create an

account
route that you'll protect with Auth0 in just a bit.

To start, create a new file called

account.js
in the
src/pages/
folder and paste in the following code:

// src/pages/account.js
import React from "react";

const Account = () => (
 <div>
  <p>This is going to be a protected route.</p>
 </div>
);

export default Account;

The above code is another super simple React component. Gatsby will automatically turn this file (and any file in this folder that exports a React component) into a route. Start the development server again with

gatsby develop
if it's not already running. You should see the following if you navigate to
localhost:8000/account
:

Gatsby basic account route.

Add Auth0 to Your Gatsby Site

You're now ready to protect the entire

account
route with Auth0. Auth0 handles identity features like user registration, email confirmation, and password reset, so you don't have to build them yourself.

Sign up for Auth0

If you don't have one yet, you will have to create a free Auth0 account now. After creating your account, go to the Applications section of your Auth0 dashboard and click on the Create Application button. Then, fill the form as follows:

  • Application Name: "Gatsby App"
  • Application Type: "Single Page Web Applications"

Try out the most powerful authentication platform for free.

Get started →

When you click on the Create button, Auth0 will redirect you to your new application's Quick Start tab. From there, head to the Settings tab and make two changes:

  1. Add
    http://localhost:8000
    to the Allowed Callback URLs field.
  2. Add
    http://localhost:8000
    to Allowed Logout URLs and Allowed Web Origins.

For security reasons, after the login and logout processes, Auth0 will only redirect users to the URLs you register in these fields.

After updating the configuration, scroll to the bottom of the page, and click Save Changes. For now, leave this page open.

Set up Gatsby with Auth0

To get started with adding Auth0 to your Gatsby app, you'll need to install Auth0's SDK for React Single Page Applications in your app. Back in the terminal, stop the development server (

Ctrl
+
C
), and issue the following command:

npm install @auth0/auth0-react

Note: This tutorial follows the Authorization Code Flow with Proof Key for Code Exchange. The Auth0 React SDK uses this under the hood. You can read more about these changes in this article by Auth0 Principal Architect Vittorio Bertocci.

Add Gatsby Auth env config

While you could manually update the variables

AUTH0_DOMAIN
,
AUTH0_CLIENTID
, and
AUTH0_CALLBACK
, it's a much better practice to create a separate environment file that's not checked in to source control.

Luckily, Gatsby ships with the library

dotenv
, so you can provide the values to the authentication service by creating a file at the root of the project called
.env.development
. Paste in the following:

# ./.env.development
# Get these values at https://manage.auth0.com
AUTH0_DOMAIN=<value>
AUTH0_CLIENTID=<value>
AUTH0_CALLBACK=http://localhost:8000/callback

Replace the placeholders with your Auth0 domain (e.g.

yourtenant.auth0.com
) and client ID. You can find both in your application's settings page.

Auth0 Dashboard Application Settings Page

You can do the same thing with production values by creating

.env.production
. Don't forget to change
AUTH0_CALLBACK
to whatever your production server is and add it to your application settings in Auth0.

Add Login to a Gatsby App with Auth0

Auth0 is now ready to use. The first step to using Auth0 is to wrap your root element in the

Auth0Provider
component. Create a
gatsby-browser.js
file at the root of your project. This file is the behind-the-scenes root component for Gatsby.

Paste in the following code:

//gatsby-browser.js
import React from 'react';
import { Auth0Provider } from '@auth0/auth0-react';
import { navigate } from 'gatsby';

const onRedirectCallback = (appState) => {
 // Use Gatsby's navigate method to replace the url
 navigate(appState?.returnTo || '/', { replace: true });
};

export const wrapRootElement = ({ element }) => {
 return (
  <Auth0Provider
   domain={process.env.AUTH0_DOMAIN}
   clientId={process.env.AUTH0_CLIENTID}
   redirectUri={window.location.origin}
   onRedirectCallback={onRedirectCallback}
   >
    {element}
 </Auth0Provider>
 );
};

Here's what's happening in this code:

  • The

    wrapRootElement
    hook from the Gatsby Browser API sets up the use of Provider components.

  • Wrap the root element in the

    <Auth0Provider>

  • Pass in the

    AUTH0_DOMAIN
    and
    AUTH0_CLIENTID
    into the
    domain
    and
    clientId
    props

  • Pass in

    window.location.origin
    to the
    redirectUri
    prop, which is the URL Auth0 will redirect your browser to with the authentication result.

  • onRedirectCallback
    removes the code and state parameters from the URL when you are redirected from the authorize page.

In this sample application, you won't be using the access token to access an API. Suppose your Gatsby application gets data using a secure API. In that case, you will use the access token stored here to access those protected resources (for example, by adding it as an

Authorization
header). Check out the Gatsby documentation on Sourcing from Private APIs to learn more about how to use private API data in your Gatsby site.

Protect a Gatsby Route with Auth0

Now that

Auth0Provider
is set up and ready to be used in Gatsby. You're going to protect the
/account
route. When logged-out users try to visit, they're redirected to the Auth0 login.

Add the new code indicated by the 👇 emojis to

account.js

// src/pages/account.js
import React from "react";
/* 👇 New code 👇 */ 
import { Link } from "gatsby";
import { useAuth0 } from "@auth0/auth0-react";
/* 👇 Import the withAuthenticationRequired HOC 👇 */ 
import { withAuthenticationRequired } from '@auth0/auth0-react';


const Account = () => {
/* 👇 Access user from the useAuth0 hook 👇 */
 const { user } = useAuth0();
  return (
  <>
   <nav>
    {/* 👇 Link to homepage */} 👇
    <Link to="/">Home</Link>
    {/* 👇 Display users email */} 👇
    <p>Email: {user.email}</p>
  </nav>
 </>
 );
};

/* 👇 Wrap the component in the withAuthenticationRequired handler 👇 */
export default withAuthenticationRequired(Account);

What's happening in this code?

  • You accessed the

    user
    object from the
    useAuth0
    hook

  • Added a link to the home page with the Gatsby

    Link
    component

  • Displayed the users' email address stored in the

    user
    object

  • Wrapped the exported

    account
    component in
    withAuthenticationRequired()

Wrapping

account
in
withAuthenticationRequired()
makes it so that when anonymous users visit the
/account
route, they will be redirected to the login page. The user will also return to the page they were visiting after successful login.

With the server running, visit http://localhost:8000/account, and you'll be redirected to the Auth0 log in.

Instead of making the user visit the

/account
path to log in, which is inconvenient. In the next section, you'll use Auth0 to allow users to choose when they want to log in with a login button.

Create a login button component

The next thing to do is to create a login button. When the user clicks this button, they will be redirected to Auth0's Universal Login page and authenticated after successful login. Inside the

src
directory, create a
components
directory, and then create a file called
LoginButton.js
in
src/components/
and paste in the code below:

// src/components/LoginButton.js
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

function LoginButton() {
 const {
  isAuthenticated,
  loginWithRedirect,
   } = useAuth0();

   return !isAuthenticated && (
    <button onClick={loginWithRedirect}>Log in</button>
  );
};

export default LoginButton;

Here's a breakdown of this code:

  • The

    useAuth0
    hook gives you access auth state and methods. In this example, you get the
    isAuthenticated
    auth state and the
    loginWithRedirect
    method from the
    useAuth0
    hook.

  • The auth state

    isAuthenticated
    checks if Auth0 has authenticated the user before React renders any component.

  • Pass

    loginWithRedirect
    to the
    onClick
    handler to redirect your users to the Auth0 Universal Login Page, where they can get authenticated.

With this component created, the next step is to add it to the index page.

Add the LoginButton component to index.js

So far, there isn't a way for the user to actually log in and get redirected to Auth0 for login and authentication. Let's import and add the

LoginButton
component to
index.js
.

Update

index.js
with the new code shown below:

// src/pages/index.js
import React from "react";
import { Link } from "gatsby";
/* 👇 New Code */ 
import LoginButton from "../components/LoginButton";


export default function Home() {
 return (
   <div>
   {/* 👇 New Code */}
    <LoginButton />
    <p><Link to="/account">Visit Your Account</Link></p>
   </div>
  );
};

Restart the Gatsby development server and navigate to

localhost:8000/account
. You should now see a button labeled login, click it, and you're directed to Auth0 to log in to your application (you will need to authorize the application the first time you log in). You'll also see your email address on the account page.

Add Logout to a Gatsby App with Auth0

Finally, you'll need a way for users to log out of your application. Inside

src/components
create a new file called
LogoutButton.js
.

Then add the following code:

// src/components/LogoutButton.js
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

function LogoutButton() {
 const {
   isAuthenticated,
   logout,
   } = useAuth0();

   return isAuthenticated && (
     <button onClick={() => {
     logout({ returnTo: window.location.origin });
    }}>Log out</button>
 );
};

export default LogoutButton;

Here is a quick recap of this code:

  • Access the
    isAuthticated
    auth state and the
    logout
    method from the
    useAuth0
    hook.
  • The
    logout()
    method redirects your users to your Auth0 logout endpoint (https://YOUR_DOMAIN/v2/logout) and then immediately redirects them to your application.

Update the account component

Now you can add a

LogoutButton
to the navigation section of the
Account
component. The finished
Account
component code will look like this:

// src/pages/account.js
import React from "react";
import { Link } from "gatsby";
import { useAuth0 } from "@auth0/auth0-react";
import { withAuthenticationRequired } from "@auth0/auth0-react";
/* 👇 New Code */ 
import LogoutButton from "../components/LogoutButton";

const Account = () => {
 const { user } = useAuth0();
 return (
  <>
   <nav>
    <Link to="/">Home</Link>
    <p>Email: {user.email}</p>
    {/* 👇 New Code */}
    <LogoutButton />
  </nav>
 </>
 );
};

export default withAuthenticationRequired(Account);

Running

gatsby develop
again, you should now be able to log in, refresh your application, and log out successfully. Congratulations!

Remember, the finished code for this tutorial is at the

gatsby-auth0
repository.

Conclusion

You now know how to implement authentication using Auth0 in virtually any Gatsby application. Feel free to explore the excellent Gatsby docs and learn more about sourcing and querying data with GraphQL, styling your application using CSS modules or CSS-in-JS, and much, much more. Most importantly, I hope you have as much fun as I do developing with Gatsby!