Using Clerk as your Identity Provider with Grafbase

Clerk provides all the necessary components to add authentication to your frontend in minutes, with only a few lines of code!

Grafbase provides the ability to configure rules to allow accessing data stored in your backend 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 Clerk as your Grafbase Identity Provider for authenticating, and authorizing requests.

Start by creating a new application, or using an existing application from your Clerk Dashboard.

Create new Clerk Application

Here you can configure your authentication preferences, and more.

After you've created a new application, create a new JWT Template:

Create new JWT template

Give your template a name, and configure the token lifetime:

Add JWT template name

You can optionally configure the Claims for your JWT if you opt to use Grafbase group based authorization.

Configure JWT claims

Make a copy of your JWT template name, and issuer URL, we'll need those later.

Inside of grafbase/schema.graphql we'll use the @auth directive to configure Clerk as our provider.

schema
  @auth(providers: [{ type: oidc, issuer: "{{ env.CLERK_ISSUER_URL }}" }]) {
  query: Query
}

Then we can configure the rules, as well as operations for accessing data.

We can restrict access to signed-in users only, as well as specific groups of users, and even control the types of operations users can perform — read, get, list, create, update, and delete.

schema
  @auth(
    providers: [{ type: oidc, issuer: "{{ env.CLERK_ISSUER_URL }}" }]
    rules: [{ allow: private }]
  ) {
  query: Query
}

If you don't have a project with Grafbase already, you can get started locally using the CLI.

npx grafbase init

Next, using the frontend API URL you got from Clerk, add it it to the file grafbase/.env:

CLERK_ISSUER_URL=
npx grafbase dev

Alternatively, add your CLERK_ISSUER_URL as a Environment Variable inside your Grafbase project settings.

Depending on your frontend stack, you'll want to use the Clerk SDK to get a valid token.

The token from Clerk must be sent as a header in the format of authorization: Bearer TOKEN along with every request to your Grafbase GraphQL API.

The schema models for Post and Comment as well as a rule for signed-in users.

Use a schema similar to the following to restrict access to only signed-in users:

schema
  @auth(
    providers: [{ type: oidc, issuer: "{{ env.CLERK_ISSUER_URL }}" }]
    rules: [{ allow: private }]
  ) {
  query: Query
}

type Post @model {
  id: ID!
  title: String!
  comments: [Comment!]!
}

type Comment @model {
  id: ID!
  message: String!
  post: Post!
}

The schema above will generate a query to fetch by collection. For example, the following query fetches all Posts:

{
  postCollection(first: 100) {
    edges {
      node {
        id
        title
        comments(first: 10) {
          edges {
            node {
              id
              message
            }
          }
        }
      }
    }
  }
}

For a frontend example, we'll use the @clerk/nextjs library to handle fetching tokens for our configured JWT template.

You can make any fetch request to your Grafbase API URL (local, or hosted) and pass along the authorization HTTP header.

Here we can await getToken({template: 'grafbase}) passing along the name of our JWT template we created earlier:

await fetch(process.env.NEXT_PUBLIC_GRAFBASE_API_URL as string, {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    authorization: `Bearer ${await getToken({
      template: 'grafbase'
    })}`
  },
  body: JSON.stringify({ query })
})

Here's what the full example looks like with Next.js:

import { useState } from 'react'
import { useAuth } from '@clerk/nextjs'

const query = `
  {
    postCollection(first: 100) {
      edges {
        node {
          id
          title
          comments(first: 10) {
            edges {
              node {
                id
                message
              }
            }
          }
        }
      }
    }
  }
`

const SchemaPage = () => {
  const [data, setData] = useState()
  const { getToken } = useAuth()

  const fetchData = async () => {
    await fetch(process.env.NEXT_PUBLIC_GRAFBASE_API_URL as string, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        authorization: `Bearer ${await getToken({
          template: 'grafbase'
        })}`
      },
      body: JSON.stringify({ query })
    }).then(res => res.json().then(({ data }) => setData(data)))
  }

  return (
    
{JSON.stringify({ data }, null, 2)}
) } export default SchemaPage

Get started with Grafbase and Clerk

Authenticate your Grafbase GraphQL requests using Clerk as an authentication provider.