Building scalable Flutter apps using Hasura, GraphQL, and event-driven serverless , Part 2 - Setting up Auth

This tutorial was written by Can Taşpınar and published as part of  the Hasura Technical Writer Program - an initiative that supports authors who write guides and tutorials for the open source Hasura GraphQL Engine.

Introduction

This is the second part in the series on "Building scalable Flutter apps using Hasura, GraphQL, and event-driven serverless". This part will cover how Hasura can work with Firebase services to provide Auth and Business Logic.

Part 1 covers how to deploy Hasura and how to model the relational data with permissions. Part 3 covers how to create the Flutter frontend.

Authentication

So far, we have used Hasura’s permission system to restrict access to certain roles. Hasura checks for the X-Hasura-User-Id header to identify which user is making the request.However, right now anyone can send this header and act as some other user. To prevent that we will use Hasura in JWT mode. When in JWT mode, Hasura will expect an Authorization header with a token. Sending a direct header like X-Hasura-User-Id will not be allowed. We are going to store X-Hasura-User-Id and the user role in the Firebase token by using custom claims.

Firebase

Create a new Firebase project and head to Authentication > Sign-in method. Enable Email/Password in providers.

For storing X-Hasura-User-Id and X-Hasura-User-Role in Firebase token, we will use the custom claims feature of Firebase Admin SDK. There are several ways to set the required claims for a user on register process. We are going to make use of Firebase Cloud Functions and create a custom sign-up function. With this function we will make sure the user will have the required claims when the sign-up process is completed. Initialize a Firebase project if you haven’t already.

$ npm install -g firebase-tools  // Install Firebase CLI
$ firebase login                 // Login to your Firebase account
$ firebase init                  // Initialize a Firebase project

Choose your project from the list and setup functions. Once the setup is completed change directory to functions folder.

$ npm install –save graphql-request

Open index.js and add the following lines. Don’t forget the replace <your-graphql-endpoint> and <your-admin-secret> with your own values.

Now that we have a function for signing up and setting up necessary claims, lets continue with creating two more functions to sync Firebase users with Hasura. These functions will act as triggers and will insert or remove users depending on the operation on Firebase. However, in Firebase, outbound requests for projects on the free plan are not allowed. You will need a billing account for this to work.

After adding these changes, go to the parent directory where you initialized your Firebase project and deploy with the following command.

$ firebase deploy

The Firebase side is done for now, let’s continue with Hasura.

Hasura

Open Heroku dashboard and click the Hasura app we have created. Head to Settings tab.We need to add some config variables for Hasura to switch to JWT mode and decode Firebase user tokens. Hit Reveal Config Vars and add following variables.

HASURA_GRAPHQL_ADMIN_SECRET -> <your-password>
HASURA_GRAPHQL_JWT_SECRET ->
{
    "type":"RS256",
    "jwk_url":"https://www.googleapis.com/service_accounts/v1/jwk/[email protected]
    com",
    "audience": "<your-firebase-app-id>",
    "issuer": "https://securetoken.google.com/<your-firebase-project-id>"
}

After setting these variables, Hasura console will be protected by the password you typed and Hasura will switch to JWT mode. When making requests to GraphQL API, we need to send the following header.

“Authorization” : Bearer <JWT TOKEN>

Event Trigger

In our quiz app, users will get 10 points if they choose the correct answers. But trusting client to increment the score wouldn’t be a good idea. Hasura has several ways to handle these kinds of cases where client can’t be trusted, or cases where some additional business logic is required. In our case we are going to make use of event triggers. We are going to create an insert trigger on the table user_answers. Whenever a new answer is inserted to this table. In case the answer is correct, score column in the user table will be incremented.

Let’s first create the function to perform these operations. Go to your Firebase project folder and open up index.js. Add the following function.

Go to the parent Firebase project directory and deploy.

$ firebase deploy

Now that the function is ready, lets add it to Hasura. Head to the Events tab in Hasura Console. Create a new trigger with the settings below. For Webhook URL, you need to paste the URL for the function we have just created. To get the function URL, open up Firebase console and head to Functions.

Now that we have the Hasura & Firebase working we can move on to building the client. In the final part we will to dive into Flutter to create the mobile app.

About the Author

Can Taşpınar is passionate and enthusiastic developer whose journey started with the question “How to make a video game?”Moving on with mobile application development and Full Stack Web development. Enjoys working with modern and open source technologies.


Hasura is an open-source engine that gives you realtime GraphQL APIs on new or existing Postgres databases, with built-in support for stitching custom GraphQL APIs and triggering webhooks on database changes.


PS: We’re hiring!