TM#010 - How to authenticate multiple Hasura roles using Firebase

TM#010 - How to authenticate multiple Hasura roles using Firebase

This article assumes that:

  1. You’ve created a Hasura and Firebase Project.
  2. You’ve already setup Firebase authentication with Hasura.
  3. You know what Hausra’s Permissions & Roles are.
  4. You know that Firebase authentication with Hasura revolves around a JWT that’s created by Firebase and fed into Hasura’s API calls.
  5. You’ve mastered the art of decoding your cat's meows and can engage in complex conversations about existential feline matters.

What are we achieving here?

At the end of this article you will know how we can setup Firebase custom claims in order to differentiate between different user types such as ‘admin’, ‘professor’, ‘student’ user types in a university’s portal. This will allow us to setup different permissions for different roles on Hasura, which will be secured and authenticated by Firebase’s JWT having custom claim embedded in it.

Yes, another tutorial with academic portal as a example, deal with it.

Understanding Firebase Custom Claims

Before we dive into the guide, we should learn what custom claims actually are. Custom claims are like superhero capes for user authentication. Basically they are additional pieces of information that can be attached to a user's authentication token in Firebase Authentication. These claims are used to define user roles or permissions beyond what is provided by default in Firebase. By utilizing custom claims, we can add custom authorization logic to our application.

In this example we’ll be configuring Firebase to attach custom claims to the JWT before sending it to the Hasura whenever the user logs in. This configuration will be done at the time of user creation aka user signup, obviously.

Here is how to do it

STEP 1: CREATE ROLES IN HASURA CONSOLE

You need to login to the hasura console of your project and go to the permissions tab of any one of the table you’ve created. You should see something like this:

No alt text provided for this image

This is the default admin (the boss) role created by Hasura that you cannot remove or modify its permissions.

In the ‘Enter new role’ enter the name of your new role, duh.

Lets say we have created two new roles: ‘Student’ and ‘Professor’.

STEP 2: WRITING THE USER SIGNUP API

I’m using Next.js API to write my code for user signup, this API caters for ‘Student’ and ‘Professor’ user type.

First, we need to initialize the application.

import { NextApiRequest, NextApiResponse } from "next";

import axios from "axios";

import {
  getAuth,
  createUserWithEmailAndPassword,
} from "firebase/auth";
import firebaseAdmin from "firebase-admin";

import {
  INSERT_PROFESSOR_MUTATION,
  INSERT_STUDENT_MUTATION,
} from "./insertOperations";

const { privateKey } = JSON.parse(process.env.PRIVATE_KEY as string)
const firebaseCreds = {
  type: process.env.TYPE,
  project_id: process.env.PROJECT_ID,
  private_key_id: process.env.PRIVATE_KEY_ID,
  private_key: privateKey,
  client_id: process.env.CLIENT_ID,
  auth_uri: process.env.AUTH_URI,
  token_uri: process.env.TOKEN_URI,
  auth_provider_x509_cert_url: process.env.AUTH_PROVIDER_X509_CERT_URL,
  client_x509_cert_url: process.env.CLIENT_X509_CERT_URL,
  client_email: process.env.CLIENT_EMAIL,
}

if (!firebaseAdmin.apps.length) {
  firebaseAdmin.initializeApp({
    credential: firebaseAdmin.credential.cert(
      firebaseCreds as firebaseAdmin.ServiceAccount
    ),
  });
}        

This API needs to know the email and password to signup a user. It should also know the user type that needs to be created.

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== "POST") {
    res.status(405).json({ error: "method not allowed" });
    return;
  }

  const { email, password, typeOfUser } = req.body;        

We’ll use firebase’s createUserWithEmailAndPassword function.

	const auth = getAuth();	
	await createUserWithEmailAndPassword(auth, email, password);
	const user = auth.currentUser;        

Here is how we’ll write the Firebase custom claim for Hasura. It’s a JSON object that is dependent on the type of user we’re signing up. The ‘x-hasura-default-role’ is the role assigned to this custom claim. The ‘x-hasura-allowed-roles’ is the list of roles that can be assumed by the role we are setting. Since ‘Student’ and ‘Professor’ have independent permissions, we’ll only keep the current role itself in the list. If for example we need an ‘Admin’ role which could do whatever ‘Professor’ and ‘Student’ combined could do, we’ll set the

	const customClaim = {
	      "<https://hasura.io/jwt/claims>": {
	        "x-hasura-default-role": typeOfUser,  //typeOfUser could be 'Student' or 'Professor' 
	        "x-hasura-allowed-roles": [
	          typeOfUser === typeOfUser,
	        ],
	        "x-hasura-user-id": user.uid,
	      },
	    };

	await firebaseAdmin.auth().setCustomUserClaims(user.uid, customClaim);        

If for example, we were assigning an ‘Administrator’ role which could do whatever ‘Professor’ and ‘Student’ combined could do, we’ll set the ‘x-hasura-allowed-roles’ like this:

	        "x-hasura-allowed-roles": [
	          "Student", "Professor"
	        ],        

The user has been created on Firebase, but we also need to store the Firebase uid in Hasura database. This is because, we’ll setup the Hasura role-based permissions using this uid. We can store it in ‘student’ or ‘professor’ table according to what type of user is signing up.

	await axios({
	      method: "POST",
	      url: process.env.NEXT_PUBLIC_HASURA_GRAPHQL_ENDPOINT,
	      headers: {
				  "content-type": "application/json",
				  "x-hasura-admin-secret": process.env.HASURA_GRAPHQL_ADMIN_SECRET,
				};
	      data: {
	        query:
	          typeOfUser === "Professor"
	            ? INSERT_PROFESSOR_MUTATION //Ezpz query
	            : INSERT_STUDENT_MUTATION, //just drag n drop in the hasura console. You know it.
	        variables: {
	          id: user.uid,
	        },
	      },
	    });

res.status(200).json({ data: "success" });

}        

Congratulations! Now ‘Student’ and ‘Professors’ can signup on your platform having their own set of permissions to different tables in your application’s database schema. Now let’s have a sneak peak of how would you configure permissions:

STEP 3: CONFIGURING ROLE-BASED (BASED) PERMISSIONS IN HASURA

Your role-based permissions would be based on the type of user that is trying to access your database. Thanks to Firebase custom roles, Hasura now knows what type of user it is through its JWT.

Here are the two permissions we are setting :

  1. We don’t want ‘Professor’ to update the student table and vice versa. But we want ‘Professor’ to be able to update their own table and vice versa.
  2. We don’t want one student updating data of another student. Same goes for professors.

The first part is fairly easy.

Go the permission tab for the professor table. Yeah the same place we created roles:

No alt text provided for this image

Here we already created ‘Professor’ and ‘Student’ roles. By default all of the permissions will be marked as a red ‘X’, which means neither of the roles have any permission for this table. Let’s change that. Click on the update permission of ‘Professor’ role. You should see something like this:

No alt text provided for this image

Expand the ‘Row update permissions’ and select ‘With custom check’. The check will be based on the ‘X-Hasura-User-Id’ aka the firebase uid extracted from the JWT. If there is a row whose ‘id’ (Firebase uid) property equals to the id from the JWT and the JWT also has the ‘Professor’ in the list of ‘x-hasura-allowed-roles’, the user can update that particular role.

Your custom check should look something like this:

No alt text provided for this image

Finally go to the ‘Column update permission’ tab and toggle the table property you want to allow to be updated under this custom check and click on ‘save permission’. The red ‘X’ mark should now change into this weird looking funnel thingy mark:

No alt text provided for this image

But wait, we don’t want to let the ‘Student’ role to update the professor table. Don’t worry, the red ‘X’ mark on the ‘Student’ update permission indicates the ‘Student’ role has no power here.

You can setup permissions for the student table in the same way.


This article was written by Muhammad Hassan Bilal , Co-Founder & CFO at Antematter.io

要查看或添加评论,请登录

社区洞察

其他会员也浏览了