Integrate Hasura 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(opens in a new tab) page. Click on the New template button to create a new template based on Hasura.
Once the Hasura template is created, you will be redirected to the template's page. You can now configure the template to your needs.
The Hasura template will pre-populate the default claims required by Hasura. You can include additional claims as necessary. Shortcodes are available to make adding dynamic user values easy.
By default, Clerk will sign the JWT with a private key automatically generated for your application, which is what most developers use for Hasura. If you so choose, you can customize this key.
Configure Hasura
The next step is to provide Hasura 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(opens in a new tab) page. Scroll down and click on Advanced. In the JWT public key section, copy the JWKS URL.
You can set up your project either with Hasura Cloud or you can run the Hasura GraphQL engine locally using Docker Compose(opens in a new tab).
Set up with Hasura Cloud
Go to your project settings, click Env vars, and then add New Env Var.
Set the key to HASURA_GRAPHQL_JWT_SECRET
and the value to the following:
{"jwk_url":"https://{{fapi}}/.well-known/jwks.json"}
Set up with Hasura Core
To add the JWT secret locally with Hasura Core, you need to set both the HASURA_GRAPHQL_ADMIN_SECRET
and HASURA_GRAPHQL_JWT_SECRET
in the docker-compose.yml
file.
HASURA_GRAPHQL_ADMIN_SECRET
can be set to any text string.
HASURA_GRAPHQL_JWT_SECRET
should be set to a stringified JSON object of the JWT secret which contains the JWKS endpoint as the value of jwk_url
.
HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkey HASURA_GRAPHQL_JWT_SECRET: '{"jwk_url":"https://{{fapi}}/.well-known/jwks.json"}'
Replace <YOUR_FRONTEND_API>
with the Frontend API value. This value can be found in the Clerk Dashboard on the API Keys(opens in a new tab) page.
With custom signing key
If you did use a custom signing key, instead of providing the jwk_url
you need to provide the algorithm type and key in the stringified JSON object as the HASURA_GRAPHQL_JWT_SECRET
in the Hasura Cloud Env Vars or in the docker-compose.yml
file.
HASURA_GRAPHQL_JWT_SECRET: '{"type": "HS256", "key": "<YOUR_SIGNING_KEY>" }'
Configure your GraphQL client
GraphQL clients (such as Apollo Client(opens in a new tab) and Relay(opens in a new tab)) 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(opens in a new tab) to validate that the authenticated requests are working properly.
Here is an example of using Apollo Client(opens in a new tab) 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 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(opens in a new tab) in conjunction with the useSWR(opens in a new tab) hook in a Next.js application to make a request to the Hasura GraphQL endpoint:
import { useAuth } from '@clerk/nextjs'; import useSWR from 'swr'; // This component needs to be a child of <ClerkProvider> and <SignedIn> // in order to access the authenticated session object const Main = () => { const { getToken } = useAuth(); const endpoint = process.env.NEXT_PUBLIC_HASURA_GRAPHQL_API; 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: 'hasura' })}` }, 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>; }; export default Main;
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.
Last updated on March 8, 2024