Managing Firebase Users with RBAC and Custom Claims

Adis Kovacevic
8 min readMay 19, 2020

--

In this article, we will add a GraphQL Auth API to our firebase project that will allow us to manage firebase users that are logging in using firebase auth. We will also grant different users different access based on their role’s and permissions using RBAC.

Firebase already gives you some visibility into the users that have logged into your applications. This API we will extend that functionality, make it easier to see all the users and change, revoke, and update users access and roles on the fly with a simple GraphQL API.

Preview

By adding the GraphQL Auth API to your Firebase app, you will be able to manage and see your Users permissions in one place

As an example, here we see a list of users, what groups they are each in, and what roles that groups has

Why RBAC?

Many applications require different levels of permissions for different types of users. An application could give users with paid subscriptions more features and access over basic users. A good way to manage this through Role Based Access Control or RBAC. With RBAC we can group our users into roles and assign different access and permissions to different roles. This gives us a flexible model to expand and grow our application.

Firebase Auth Token

When a user signs in with any of the available providers, Google for example, a firebase token is generated and returned to the application. This token can carry custom claims as well as the the default values provided by the firebase and the auth provider.

We will manage a user’s access by adding our roles and groups to the firebase token, letting our client app and any other app the credentials are passed, use the roles and permissions to authorize the users access. The firebase token with roles and groups will look something like this

Why a separate project for RBAC management?

Separation of concerns

Don’t clutter up your application codebase with code solely designed to manage roles and permissions for users. That’s a feature probably only used by a few admins of the application.

Speed to market

The management of roles and permissions is not what makes your app unique. It just slows the speed to market for your application. An off the shelf solution would work nicely here.

Let’s get Started

Installing the Auth API

Pull the following GitHub project down

Follow the steps in the README to setup the project and point to your existing firebase project.

In the root, update the .firsbaseserc file to be your firebase project with the existing app you wish to enhance with role based management.

For example, my project is “adis-test2” so my .firebaserc file looks like this

Now run the deploy command in the functions directory

npm run deploy

The project only deploys its own endpoints without deleting or updating the existing functions/hosting you might have in your firebase project

You should see 3 new functions along side your apps in firebase

Deployed Functions

Configuring the Application

Enabling Firestore

Ensure you create a Cloud Firestore if you project does not have one already. In the Database section for Firebase, click create database

Click Next, then Done. Wait for the settings to apply.

Adding the default User

In firebase manually add the admin user (can be deleted once you make another account admin)

Click Authentication in the left panel and click set up sign-in method

Enable Email/Password

Add admin@admin.com

You can now use the GraphQL API with the above user by generating a token. If you already know how to get tokens from logins skip the next section and go straight to using the GraphQL API

Getting a token to use for the API

You can snag yourself a token by signing in via a front-end app. If your project does not have one, you can use the prebuilt ones from firebase here

https://firebase.google.com/docs/auth/web/firebaseui

Add your app in the Firebase project settings and configure your application with the settings provided by Firebase

Here is my configuration. Ensure that Email/Password is a sign in option for your app as you will initially need to login as admin@admin.com

Once your hosted app is deployed you should see the domains sections under the Hosting section of Firebase

Follow the link and go to the sign in page

Sign in with email as admin@admin.com and the password you created for that user

You should see the token in the browser url when the browser redirects back to your web app.

eyJhbGciOiJSUzI1NiIsImtpZCI6ImY1YzlhZWJlMjM0ZGE2MDE2YmQ3Yjk0OTE2OGI4Y2Q1YjRlYzllZWIiLCJ0eXAiOiJKV1QifQ.eyJhZG1pbiI6dHJ1ZSwiaXNzIjoiaHR0cHM6Ly9zZWN1cmV0b2tlbi5nb29nbGUuY29tL2FkaXMtdGVzdDIiLCJhdWQiOiJhZGlzLXRlc3QyIiwiYXV0aF90aW1lIjoxNTg5OTA3NjUxLCJ1c2VyX2lkIjoiVHlLMzl4dzgxSWdyeXByUUU2M1d4WmRiNmlNMiIsInN1YiI6IlR5SzM5eHc4MUlncnlwclFFNjNXeFpkYjZpTTIiLCJpYXQiOjE1ODk5MDc2NTEsImV4cCI6MTU4OTkxMTI1MSwiZW1haWwiOiJhZG1pbkBhZG1pbi5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsiYWRtaW5AYWRtaW4uY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.XafTof-o6hC8VDTzU9lgUtLDfJk99A9NV7vFjodqGSa9TTiW9xb5LS-caBs9BNpK5E-zc9SRNU_IJsBHEfRg1enIYkCCzCIV2ynyAZNpQk-ApxuqFTv0_JjpE4WhR9-Pr21Sbx3drBQZ4GNpZDEE0OueVL6Zr3s7RUq-BluzYtVJM1j8Ctcns007MPlKBelwWN7gAsnuruNUfuRWkQnVOdozT-x0bdBUOMZbRxc8te4fv_BobQ6XU2w2–3wVXAVrtNy8Y9hpLYpBaPDmNsXE0Aqkm9az-8UpkNjwDpoGpciO0narVuYlRLDSKxOEBV9spGaNsCSEHpraRzGP374-wA

decoding the token (jwt.io) will show us that the token is valid and has admin privileges

Using the token in the GraphQL API

Navigate to your GraphQL API endpoint by navigating to your function with that ends in auth-graphql. For reference, my path is :

https://us-central1-adis-test2.cloudfunctions.net/auth-graphql

at the bottom left, add your auth token for authorization with the api

add the following HTTP Header

{
"Authorization": "Bearer <YOUR FIREBASE TOKEN>"
}

We are all set to use the Auth API!

Managing Users

I’m going to sign in to my firebase app with Google to simulate a new User logging in. Make sure Google it is enabled as a sign-in method in your Firebase console.

When a first time user logs in, the auth-userCreated function will be triggered, and the function will add the user to Firestore and any default onboarding desired. Likewise when the user is deleted, the auth-userDeleted function will remove him from Firestore.

We should now see the user in our GraphQL API when we query for all users

query {
users (input: {
size: 10
page: 1
}){
uid
admin
email
photoURL
}
}

Success! Let’s make them an admin so we don’t have to rely on the admin@admin.com User anymore. The call requires the uid from the user, which we can get from the previous call to get users.

mutation {
makeAdmin(uid: "NFaKhH0XW8dzRqD9cAkv2uMRksb2") {
admin
email
}
}

Now when they sign-in again, the token as the admin flag set to true

He has a groups property but isn’t a member of any of the RBAC groups, let’s do that next.

Adding Roles

Let’s add a role using the API. I will add a student role that has 2 permissions.

In Firestore you will now see a new roles collection with the student document. Success!

Adding Groups

Let’s add a new group so we can better arrange the permissions of our users. I Will be adding a Teachers groups as well as a 5th graders group. Using the GraphQL API

create 5th graders Group

mutation {
createGroup(input: {
name: "5th_grade"
}){
name
}
}

create teachers Group

mutation {
createGroup(input: {
name: "teachers"
}){
name
}
}

Adding Roles to Groups

Let’s add the student Role to the 5th graders group, giving them the permissions reader and editor

mutation {
addRoleToGroup(input:{
roleName:"student"
groupName:"5th_grade"
}) {
name
hasRoles {
name
permissions
}
}
}

Adding Users to Groups

Let’s make our user part of the teachers Group

mutation {
addUserToGroup(input: {
userId: "NFaKhH0XW8dzRqD9cAkv2uMRksb2"
groupName: "teachers"
}) {
uid
email
inGroups {
name
hasRoles
}
}
}

Looking at an updated Firebase token we should see that group

Done

Excellent! Our Firebase apps can now use the RBAC permissions directly from the Firebase token to provide access to different features, capabilities, api routes, etc. Our admins can manage all our Users and their Groups/Roles/Permissions in 1 place, easily adding and removing permissions.

It’s quick and easy to list all the groups, their permissions, and what users are assigned to what groups :

query {
groups(input:{
size:10
page:1
}) {
name
members {
email
}
hasRoles {
name
permissions
}
}
}

Additions

In the future, a front-end client can then also be added to the api to provide a dashboard for users and roles to provide admins even easier access to manage large sets of users, groups, roles, and permissions.

--

--