Skip to content

Instantly share code, notes, and snippets.

@Ekwuno
Forked from twclark0/add-auth0-recipe.mdx
Created May 7, 2020 12:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ekwuno/5a3bf30e94bb8584bc70d15ef275b65f to your computer and use it in GitHub Desktop.
Save Ekwuno/5a3bf30e94bb8584bc70d15ef275b65f to your computer and use it in GitHub Desktop.

Add Authentication with Auth0 to a Gatsby site

All the pieces of authentication are possible in Gatsby. Thanks to Auth0, setting it up doesn't have to be so cumbersome!

This setup comes straight from Auth0's official quick start for React.


The first step is installing the official Auth0 SDK for JavaScript from npm.


Auth0 provides some boilerplate code in their quick start that will provide some nice functions to access the user and silently reauthenticate them on your site.

The code there sets up a React hook that gives you the ability to:

  • access tokens - using functions like getIdTokenClaims and getTokenSilently
  • access user data - using the user object
  • check the authenticated state - using isAuthenticated
  • see if Auth0 is still initializing - using the loading boolean

The next recipe step will ask you to add it.


This is the boilerplate code from Auth0:


To encapsulate everything in one place, this recipe will generate a new local plugin to let the rest of the Gatsby app access the boilerplate code.

The index.js and package.json files are needed for plugins:


Inside of gatsby-browser we will wrap out app with the auth provider created in auth.js. A provider comes from React's context API and allows access to data or functions in any component or file in your app below it in the React tree. This gives the rest of your app access to authentication information and functionality.


Now, with the code added, you can install the local plugin in your Gatsby config. The options for domain and clientId are passed in.

You will need to replace the values with your own Auth0 app's client id and domain. The example values will not work until you change them.

<GatsbyPlugin name="gatsby-plugin-auth0" options={{ domain: yourdomain.auth0.com, clientId: s0m3r4nd0mCh4raCT3rZ, }} />


On the Auth0 side, all you need to ensure is that you have created an app and within that app you have added http://localhost:8000 to Allowed Callback URLs, Allowed Logout URLs, and Allowed Web Origins.


To test that it's working, this recipe will add an example page at http://localhost:8000/example-account where you can test by clicking on the login button, which will redirect you to Auth0's hosted login page.

You will see a user logged in the console when you login, and can use the useAuth0 hook by importing it from the local plugin on any page or in any componoent.

import React, { useState, useEffect, useContext } from "react"
import createAuth0Client from "@auth0/auth0-spa-js"
const defaultContext = {
isAuthenticated: false,
user: null,
loading: false,
popupOpen: false,
loginWithPopup: () => {},
handleRedirectCallback: () => {},
getIdTokenClaims: () => {},
loginWithRedirect: () => {},
getTokenSilently: () => {},
getTokenWithPopup: () => {},
logout: () => {},
}
export const Auth0Context = React.createContext(defaultContext)
export const useAuth0 = () => useContext(Auth0Context)
export const Auth0Provider = ({
children,
onRedirectCallback,
...initOptions
}) => {
const [isAuthenticated, setIsAuthenticated] = useState()
const [user, setUser] = useState()
const [auth0Client, setAuth0] = useState({})
const [loading, setLoading] = useState(true)
const [popupOpen, setPopupOpen] = useState(false)
useEffect(() => {
const initAuth0 = async () => {
const auth0FromHook = await createAuth0Client(initOptions)
setAuth0(auth0FromHook)
if (
window.location.search.includes("code=") &&
window.location.search.includes("state=")
) {
const { appState } = await auth0FromHook.handleRedirectCallback()
onRedirectCallback(appState)
}
const isAuthenticated = await auth0FromHook.isAuthenticated()
setIsAuthenticated(isAuthenticated)
if (isAuthenticated) {
const user = await auth0FromHook.getUser()
setUser(user)
}
setLoading(false)
}
initAuth0()
// eslint-disable-next-line
}, [])
const loginWithPopup = async (params = {}) => {
setPopupOpen(true)
try {
await auth0Client.loginWithPopup(params)
} catch (error) {
console.error(error)
} finally {
setPopupOpen(false)
}
const user = await auth0Client.getUser()
setUser(user)
setIsAuthenticated(true)
}
const handleRedirectCallback = async () => {
setLoading(true)
await auth0Client.handleRedirectCallback()
const user = await auth0Client.getUser()
setLoading(false)
setIsAuthenticated(true)
setUser(user)
}
return (
<Auth0Context.Provider
value={{
isAuthenticated,
user,
loading,
popupOpen,
loginWithPopup,
handleRedirectCallback,
getIdTokenClaims: (...p) => auth0Client.getIdTokenClaims(...p),
loginWithRedirect: (...p) => auth0Client.loginWithRedirect(...p),
getTokenSilently: (...p) => auth0Client.getTokenSilently(...p),
getTokenWithPopup: (...p) => auth0Client.getTokenWithPopup(...p),
logout: (...p) => auth0Client.logout(...p),
}}
>
{children}
</Auth0Context.Provider>
)
}
import React from "react"
import { useAuth0 } from "../../plugins/gatsby-plugin-auth0"
const Account = () => {
const { isAuthenticated, loading, logout, user, loginWithPopup } = useAuth0()
if (loading) {
return <p>Loading...</p>
}
return (
<div>
{isAuthenticated ? (
<>
<button onClick={() => logout()}>Log out</button>
<p>Check out the user data supplied by Auth0, below:</p>
<pre>{isAuthenticated && JSON.stringify(user, null, 2)}</pre>
</>
) : (
<>
<h2>Hi, try logging in:</h2>
<button onClick={() => loginWithPopup()}>Log in</button>
</>
)}
</div>
)
}
export default Account
import React from "react"
import { Auth0Provider } from "./auth"
import { navigate } from "gatsby"
const onRedirectCallback = (appState) =>
appState && appState.targetUrl && navigate(appState.targetUrl)
export const wrapRootElement = ({ element }, pluginOptions) => {
return (
<Auth0Provider
domain={pluginOptions.domain}
client_id={pluginOptions.clientId}
redirect_uri={window.location.origin}
onRedirectCallback={onRedirectCallback}
>
{element}
</Auth0Provider>
)
}
import { useAuth0 } from "./auth"
export { useAuth0 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment