Docs

Integrate Nhost with Clerk

The first step is to create a new Clerk application from your Clerk Dashboard if you haven’t done so already. You can choose whichever authentication strategy and social sign-in providers you prefer. For more information, check out our Set up your application guide.

After your Clerk application has been created, go to the Clerk Dashboard and navigate to the JWT Templates page. Click on the New template button to create a new template based on Nhost.

The JWT Templates page in the Clerk Dashboard. The 'New template' button was clicked, and a pop up titled 'New JWT template' is shown. The 'Nhost' template is hovered over.

Once the Nhost template is created, you will be redirected to the template's page. You can now configure the template to your needs.

The 'Create new template' page of the JWT Templates page in the Clerk Dashboard.

The Nhost template will pre-populate the default claims required by Nhost and Hasura. You can include additional claims as necessary. Shortcodes are available to make adding dynamic user values easy.

The 'Create new template' page of the JWT Templates page in the Clerk Dashboard. The page is scrolled down to the 'Claims' section.

Configure Nhost

The next step is to provide Nhost with the public keys used to verify the JWT issued by Clerk. Assuming you didn’t use a custom signing key, set the JWKS endpoint field to the JSON Web Key Set (JWKS) URL Clerk automatically created with your Frontend API at https://<YOUR_FRONTEND_API>/.well-known/jwks.json

You can find this URL in the Clerk Dashboard on the API keys page. Scroll down and click on Advanced. In the JWT public key section, copy the JWKS URL.

The API Keys page in the Clerk Dashboard. A red box outlines the 'Advanced' drop down button. A red arrow is pointing to the copy button next to 'JWKS URL' in the 'JWT public key' section.

From your Nhost dashboard, navigate to Settings --> Environment variables.

The Environment variables page in the Nhost dashboard.

Next to the NOHST_JWT_SECRET, click the Edit button and paste in the JWKS URL that you copied from the Clerk Dashboard.

With custom signing key

If you used a custom signing key, instead of providing the jwk_url, you need to provide the algorithm type and key as a JSON object in the NHOST_JWT_SECRET field.

{ "type": "HS256", "key": "<YOUR_SIGNING_KEY>" }

Configure the providers

Both Nhost and Clerk have Provider components that are required to wrap your React application to provide the authentication context.

This is how you would set up a Next.js application using both Providers:

import { NhostNextProvider, NhostClient } from '@nhost/nextjs'
import { ClerkProvider, RedirectToSignIn, SignedIn, SignedOut } from '@clerk/nextjs'

const nhost = new NhostClient({
  subdomain: process.env.NEXT_PUBLIC_NHOST_SUBDOMAIN || '',
  region: process.env.NEXT_PUBLIC_NHOST_REGION || '',
})

function MyApp({ Component, pageProps }) {
  return (
    <NhostNextProvider nhost={nhost} initial={pageProps.nhostSession}>
      <ClerkProvider {...pageProps}>
        <SignedIn>
          <Component {...pageProps} />
        </SignedIn>
        <SignedOut>
          <RedirectToSignIn />
        </SignedOut>
      </ClerkProvider>
    </NhostNextProvider>
  )
}

export default MyApp

Configure your GraphQL client

GraphQL clients (such as Apollo Client and Relay) can help with querying and caching your data. They can also manage UI state, keep data in sync, and boost performance. GraphQL requests can be to the Hasura backend using different clients.

The last step of integrating Clerk as the modern web authentication solution for Hasura is to pass the JWT in the Authorization header with your requests. You can access the token generated with the Hasura claims by calling getToken({ template: <your-template-name> }) on the Session object with the name of your template.

Even if you don’t have a database table set up yet, we can make use of the built-in GraphQL introspection system to validate that the authenticated requests are working properly.

Here is an example of using Apollo Client in conjunction with the useAuth() hook in a Next.js application to make a request to the Hasura GraphQL endpoint:

import { ApolloProvider, ApolloClient, HttpLink, from, InMemoryCache } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'
import { useAuth } from '@clerk/nextjs'

export const ApolloProviderWrapper = ({ children }) => {
  const { getToken } = useAuth()
  const apolloClient = useMemo(() => {
    const authMiddleware = setContext(async (req, { headers }) => {
      const token = await user.getToken({ template: 'template' })
      return {
        headers: {
          ...headers,
          authorization: `Bearer ${token}`,
        },
      }
    })

    const httpLink = new HttpLink({
      uri: process.env.GRAPHQL_URI,
    })

    return new ApolloClient({
      link: from([authMiddleware, httpLink]),
      cache: new InMemoryCache(),
    })
  }, [getToken])

  return <ApolloProvider client={apolloClient}>{children}</ApolloProvider>
}

As an alternative, here is an example of using Fetch API in conjunction with the useSWR hook in a Next.js application to make a request to the Hasura GraphQL endpoint:

import { useAuth } from '@clerk/nextjs'
import useSWR from 'swr'

export default function Home() {
  const { getToken } = useAuth()
  const subdomain = process.env.NEXT_PUBLIC_NHOST_SUBDOMAIN
  const endpoint = `https://${subdomain}.nhost.run/v1/graphql`
  const query = `query { __schema { types { name } } }`
  const fetcher = async (...args) =>
    fetch(...args, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
        Authorization: `Bearer ${await getToken({ template: 'nhost' })}`,
      },
      body: JSON.stringify({ query }),
    }).then((res) => res.json())

  const { data } = useSWR(endpoint, fetcher)

  return <p>GraphQL schema has {data?.data?.__schema.types.length} types</p>
}

Note that the getToken({ template: <your-template-name> }) call is asynchronous and returns a Promise that needs to be resolved before accessing the token value. This token is short-lived for better security and should be called before every request to your GraphQL API. The caching and refreshing of the token is handled automatically by Clerk.

Feedback

What did you think of this content?

Last updated on