Auth0 prides itself on easy setup, adaptable authentication and authorization patterns. It ships with a hosted auth page, and plugins for your frontend application for managing user sessions.
Grafbase provides the ability to configure rules to allow accessing data stored in your Grafbase Database for signed-in users, specific groups of users, and rules for only reading, creating, updating, or deleting data.
In this guide we'll show you how to configure Auth0 as your Grafbase Identity Provider for authenticating, and authorizing requests.
We'll be using Next.js but if you're something else on the frontend, Auth0 has lots of plugins that are easy to get started with.
Start by creating a new application, or locating an existing application you want to use with Grafbase from your Auth0 Dashboard.
Once you've created the application, go to the Settings > Basic Information
panel and copy the following values for use later:
- Domain
- Client ID
- Client Secret
Now inside the panel for Application URIs
add these settings:
- Allowed Callback URLs:
http://localhost:3000/api/auth/callback
- Allowed Logout URLs:
http://localhost:3000/
Let's begin by creating the frontend for our Auth0 app.
npx create-next-app nextjs-auth0
You'll then be asked some questions on how the CLI should initialize your new Next.js app. Pick your own preferences here but if here's the configuration we'll use for the rest of the guide:
✔ Would you like to use TypeScript with this project? … Yes
✔ Would you like to use ESLint with this project? … Yes
✔ Would you like to use `src/` directory with this project? … No
✔ Would you like to use experimental `app/` directory with this project? … No
✔ What import alias would you like configured? … @/*
We'll be using the nextjs-auth0
library to reduce the boilerplate needed when working with Next.js and Auth0.
Run the following NPM command inside the root of your new nextjs-auth0
application:
npm install @auth0/nextjs-auth0
Now create the file pages/api/auth/[...auth0].ts
and add the following:
import { handleAuth } from '@auth0/nextjs-auth0'
export default handleAuth()
Now update pages/_app.tsx
to import UserProvider
and wrap your Component
with it:
import { UserProvider } from '@auth0/nextjs-auth0/client'
import type { AppProps } from 'next/app'
export default function App({ Component, pageProps }: AppProps) {
return (
<UserProvider>
<Component {...pageProps} />
</UserProvider>
)
}
Finally finish by updating pages/index.tsx
to contain some basic code to allow users to login and logout:
import { useUser } from '@auth0/nextjs-auth0/client'
export default function Index() {
const { user, error, isLoading } = useUser()
if (isLoading) return <div>Loading...</div>
if (error) return <div>{error.message}</div>
if (user) {
return (
<>
Signed in
<br />
<a href="/api/auth/logout">Logout</a>
</>
)
}
return <a href="/api/auth/login">Login</a>
}
We're almost there but before we can test everything works, we must first add the environment variables.
We need to generate a secret value for AUTH0_SECRET
that is used to encrypt the session cookie:
node -e "console.log(crypto.randomBytes(32).toString('hex'))"
Then create the file .env
in the root of your project and add the values obtained in step 1:
AUTH0_SECRET=
AUTH0_BASE_URL=http://localhost:3000
AUTH0_ISSUER_BASE_URL=
AUTH0_CLIENT_ID=
AUTH0_CLIENT_SECRET=
AUTH0_AUDIENCE=https://grafbase.com
NEXT_PUBLIC_GRAFBASE_API_URL=http://localhost:4000/graphql
We'll be using the Grafbase CLI locally which we'll setup later. Make sure to set NEXT_PUBLIC_GRAFBASE_API_URL
to http://localhost:4000/graphql
.
If you now start the Next.js development sever and go to http://localhost:3000
you should be redirected to the Auth0 page to login or create an account.
npm run dev
Once you've signed in you should now see the see the text Signed in
:
In the root of your nextjs-auth0
project directory run the following command:
npx grafbase init
You should now see that the file grafbase.config.ts
was automatically generated.
Open the configuration file and replace the contents with the below:
import { auth, config, graph } from '@grafbase/sdk'
const g = graph.Standalone()
const provider = auth.OpenIDConnect({
issuer: g.env('AUTH0_ISSUER_BASE_URL'),
})
const message = g.type('Message', {
id: g.id(),
content: g.string(),
})
g.query('messages', {
returns: g.ref(message).list(),
resolver: 'messages',
})
export default config({
graph: g,
auth: {
providers: [provider],
rules: rules => {
rules.private()
},
},
})
Here we configure the OpenID Connect (oidc
) provider and a messages
field resolver we can use to test authenticated requests.
Next add the AUTH0_ISSUER_BASE_URL
to the file .env
:
AUTH0_ISSUER_BASE_URL
The AUTH0_ISSUER_BASE_URL
value must match the value set in the root .env
(provided by Auth0).
Now start the Grafbase development server:
npx grafbase dev
Make sure to add AUTH0_ISSUER_BASE_URL
as an Environment Variable inside your Grafbase graph settings when deploying your API.
So that we can successfully send a request to Auth0 we must first generate an access token.
We can do this using the method getAccessToken
from @auth0/nextjs-auth0
.
Create the file pages/api/auth/token.ts
and add the following:
import { getAccessToken, withApiAuthRequired } from '@auth0/nextjs-auth0'
import { NextApiRequest, NextApiResponse } from 'next'
async function handler(req: NextApiRequest, res: NextApiResponse) {
const { accessToken: token } = await getAccessToken(req, res, {
authorizationParams: {
audience: 'https://grafbase.com',
},
})
res.json({ token })
}
export default withApiAuthRequired(handler)
We're now ready to make requests to our GraphQL API from the Next.js frontend using the access token generated by Auth0.
We'll now update pages/index.tsx
to contain a query to fetch messages from the API.
Next inside pages/index.tsx
add the following functions:
const fetchToken = async () =>
await fetch('/api/auth/token').then(res => res.json())
const fetchMessages = async () => {
const { token } = await fetchToken()
return fetch(process.env.NEXT_PUBLIC_GRAFBASE_API_URL!, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
query: /* GraphQL */ `
{
messages {
content
}
}
`,
}),
})
.then(res => res.json())
.catch(err => console.log(err))
}
You can see above that the fetchMessages
function makes a request to fetchToken
(the API route /api/auth/token
we created previously) and returns the response as JSON.
Once the token is received we then pass that onto the Grafbase backend inside of the Authorization
header.
Now update the Index
component to import useState
and add a button that calls the fetchMessages
function:
import { useState } from 'react'
export default function Index() {
const [data, setData] = useState()
const { user, error, isLoading } = useUser()
if (isLoading) return <div>Loading...</div>
if (error) return <div>{error.message}</div>
if (user) {
return (
<>
Signed in
<br />
<a href="/api/auth/logout">Logout</a>
<br />
<button
onClick={() => fetchMessages().then(({ data: res }) => setData(res))}
>
Fetch messages with token
</button>
<pre>{JSON.stringify({ data }, null, 2)}</pre>
</>
)
}
return <a href="/api/auth/login">Login</a>
}
That's it! You should now be able to authenticate with your Grafbase backend using the access token issued by Auth0.