Setting Up A Multi-Tenant Application With Firebase, GraphQL, and Angular

Share on facebook
Share on google
Share on twitter
Share on linkedin

In this post, I will show you, how to set up a multi-tenant application with Firebase, GraphQL, and Angular. This is a common scenario for SaaS applications, as multiple tenants should be able to have their data separated from other tenants’ data and that data should be kept safe as well using proper authorization checks.

We will cover, how to design the Firebase Firestore database and setup Firebase Authentication to support multiple tenants as well as how to implement the necessary authorization checks on a GraphQL NodeJS server hosted with Firebase functions. There is going to be an Angular app, containing the course portal, which among others, are used for Angular Architect Accelerator.

Design the Firestore database

First, we are going to design our Firestore database to support multiple tenants. We are going to do this, by creating a schools collection, containing the different schools (tenants). The tenant’s data are then nested under these schools, that way the tenant’s data is split among separate vertical slices, which makes the security and tenant management easier.

Under each school (tenant), the tenant data is users (containing user-specific data), and course collection. Each course includes sections, lessons, and resources collections (containing the necessary data for each school).

On the top level, the schools collection contains the tenants, which contains courses and users:

 

 

Each course contains sections, resources, and lessons, where the sections contain a list of referenced lessons:

We store user data such as completed lessons and action items on each users’ entry:

 

 

 

Having that set up, our database now supports multiple-tenants, as well as user and course-specific data for each tenant.

Activating multi-tenant login

To support multi-tenant authentication we will use Firebase Authentication + Google Cloud Platforms’ Identity Platform, which will provide us with multi-tenant support.

You will need to go to Identity Platform in Google Cloud Platform and enable it. Here you can create tenants and add users to a specific tenant.

Integrating with the GraphQL server

We need to do these things in the GraphQL server:

  1. Verify id token on the requester and setting role and tenant id to each resolver, so we have it handy for all resolvers
  2. Use the tenants when reading and writing from/to Firestore

Verify id token and set context

For convenience, we want to get the schoolId from an HTTP header, we are setting in our GraphQL context, so we can access it in every query/mutation without the client needing to provide it explicitly in the GrahQL payload.
Also, we want to get the user id and validate, that the requesting user has a valid token. We are using Firebase Authentication for authentication on the Angular client.

We set this data, as well as verifies the id token in the Apollo server context middleware (on our GraphQL NodeJS server):

Use the context in the resolvers

In the queries and mutations, we want to check, that the uid in a payload, matches the current user’s userid (which we get from context) or the user is an admin of that user’s school.

Here we are using the context data to check if the requesting user is authorized to update the lesson’s completed status and is using the schoolId (tenantId) to update Firestore.

Setting up the clients for multi-tenancy

Since the clients need to tell the server on each request, which school it belongs to, it is convenient to do that using a header in an HTTP interceptor.

In this snippet, the schoolId and idToken is set as HTTP headers on each request and is used in the Apollo context as shown in the previous section.

Clients routing flow

For the routing, we need the route to start with the schoolId param, so we can set the school id.

The SchoolIdResolver is setting the Firebase Authentication tenant id:

After the user is logged in, it is navigated to a page for selecting the course:

Conclusion

What’s it! Now multiple tenants can use your application and have their data nicely separated and secured on your backend. Also, we saw how to make it simple for the clients to provide the tenant identifier (schoolId) to the server on each request, as well as having the routing set up for multi-tenancy.

Do you want to become an Angular architect? Check out Angular Architect Accelerator.

Related Posts and Comments

Error, loading, content…? Use this page pattern for your Angular apps

When developing Angular applications, it’s common for pages to transition through three key states: error, loading, and show content. Every time you fetch data from an API, your page will likely show a loading indicator first, and then either render the content successfully or display an error message if something goes wrong. This pattern is

Read More »

How to Set up a CI pipeline with Azure Pipelines and Nx

It goes without saying that having a CI pipeline for your Angular apps is a must. Setting one up for regular Angular apps is fairly straightforward but when you have an Nx monorepo there are certain other challenges that you have to overcome to successfully orchestrate a “build once, deploy many” pipeline. This post will

Read More »

Leave a Comment

Your email address will not be published. Required fields are marked *