Hasura Authentication and Authorization with Auth0.
I had to hunt for this solution, so while it's easy to implement, finding the correct incantation is not. Reference my previous post on setting up Gatsby with Auth0 for a complete solution.
Hasura has several ways to do Authentication and Authorization. You can find the documentation here.
Setting up custom JWT
We want to use a JWT (JSON Web Token) provided by Auth0. To make this happen, we need Auth0 to add some extra information to the JWT. We do this with Auth0 Rules. Go to the Dashboard and choose Rules on the lefthand menu. Create a new Rule with any name that makes sense and paste in this code.
function (user, context, callback) { const assignedRoles = (context.authorization || {}).roles; const namespace = ""; context.idToken[namespace] = { 'x-hasura-default-role': 'user', 'x-hasura-allowed-roles': assignedRoles, 'x-hasura-user-id': user.user_id }; callback(null, user, context); }
Note: When we make the GraphQL call to Hasura, we need to provide a user role that the the query will be executed as. This needs to be one of the assigned roles. If we don't specify a Role the the Role will default to 'user',
Setting Up Roles and Users
Go to the Auth0 Dashboard and choose Users & Roles > Roles on the lefthand menu. Create a new test Role here. Now go to Users & Roles > Users and add the new Role to a user.
Try it
To test, all we need to do is log into the Gatsby and print out the JWT. Copy the JWT and paste it into to decode it and see the additional fields.
Now you can set up Hasura table permissions using the new Role.
Securing Hasura Admin and JWT mode activation
You need to crate a
HASURA_GRAPHQL_JWT_SECRET and add it to our environmental varaibles in Heroku. Use this like to create the secret.
Now add the environmental variable. Go to the Settings tab and click 'Receal Config Vars'.
You can also add an
HASURA_GRAPHQL_ADMIN_SECRET to override the Admin Console authentication.
You can set the table permissions like this.
Use these headers to test the GrqphQL.
Apollo Client
Calling from the Apollo client would look sonething like this.
import React from 'react' import { ApolloProvider } from '@apollo/react-hooks' import ApolloClient from 'apollo-boost' import fetch from 'isomorphic-fetch' import { getIdToken, getProfile } from './auth' const client = new ApolloClient({ uri: process.env.GATSBY_HASURA_URL, fetch, request: (operation) => { const token = getIdToken() const profile = getProfile() console.log('set auth to ', profile) operation.setContext({ headers: { authorization: token ? `Bearer ${token}` : '', 'x-hasura-role': profile ? profile.role : '', }, }) }, }) const ApolloRootElementWrapper = ({ element }) => ( <ApolloProvider client={client}>{element}</ApolloProvider> ) export default ApolloRootElementWrapper