Managing Firebase Users with RBAC and Custom Claims
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
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.