Hasura + Heroku + Firebase — Firebase Authentication and Hasura Authorization to an iOS app

Hasura + Heroku + Firebase + iOS

Today, I come up with big topic. Yeah! “Backend”. I been an iOS developer for last 4 years. My curiosity level becomes higher on backend stuffs in the recent days. So, I’ve planned to be a backend developer for my own iOS app. I strongly recommended to explore Hasura if you are new to backend related things. Hasura is an open source service instant realtime GraphQL APIs engine. It gives you production-grade APIs on your data without having to build, operate & scale a GraphQL server. Using Hasura, you can build modern apps and APIs much faster than other. You can learn more about Hasura here.

Let’s get into the topic. I have separated the topic into 5 sessions:

  1. Hasura — Hasura account creation and project console setup
  2. Heroku — Heroku account creation and app setup with configurations
  3. Firebase — Project setup and Deploying cloud function
  4. Hasura — Table creation and setting up user permission
  5. Integrate Firebase Auth and fetch data from Hasura database using graphql query with authorizarion token.

Hasura

Create account:

We need to create our own account in hasura.io

Create project:

Give some unique name to create new project in the hasura dashboard. Once your project is successfully initiated, you can see like this:

Hasura Project Dashboard

When you tap on the Launch Console CTA, it redirects to the projects console.

Hasura Project Console

Create database:

Go to Data section and there you can find connect database CTA over the data manager section. You can see couple of option to connect database. First option is connect your existing database and the another one is create Heroku database. We only focus on the Heroku database creation since we are beginners for this backend stuffs 😅.

Hasura Connect Database

To create database in Heroku, we need to have account on this. Lets jump there and we will come back here again.

Heroku

Heroku is a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud. You can read more about this here.

Create account:

We need to create our own account in heroku.com.

Back to Hasura:

Now you see the Heroku account linked to Hasura dashboard in the account settings. If its not linked automatically , you need to add manually.

Hasura Account Settings

Hasura console:

Now, we are going to continue the heroku’s database creation. Tap on the ‘Create Database’ CTA.

Create Heroku Database

It will create a new app in Heroku dashboard with Postgres database for our projects and linked to hasura.

Connecting Heroku

Woot! 🍻 Heroku database was connected to Hasura.

Connected Heroku’s database

Thats it guys! We have created our database. Next, we need to do create tables and user role permissions used for authorization in the hasura console and some configuration in Heroku for authorization and authentication works. Don’t worry about this for now. Will make it simple as possible 💪. We will do the Hasura table creation after the Firebase setup and configurations.

Firebase

Create project:

We need to create firebase project in the firebase console.

Deploy cloud function:

A cloud function is a function that automatically runs — in response to events triggered by Firebase features and HTTPS requests. In our case, the event is firebase user creation. When that happens, we would like to add some extra data to the user’s id token. I recommeded to follow the setps required to deploy the cloud function in firebase official site. You can check here: https://firebase.google.com/docs/functions/get-started

Step 1: Set up Node.js

First, install firebase tools in your mac. To do this, open terminal and run the following command:

~ npm install -g firebase-tools

Step 2: Initialize firebase project

Once firebase tools installed, you need to run the following firebase commands one by one to configure your firebase project

~ firebase login
~ firebase init firestore
~ firebase init functions

Finally, you will get like this:

Downloaded Firebase Function

Setp 3: Add cloud function

Open index.js file and paste the following code:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);
exports.processSignUp = functions.auth.user().onCreate((user) => {
const customClaims = {
"https://hasura.io/jwt/claims": {
"x-hasura-default-role": "user",
"x-hasura-allowed-roles": ["user"],
"x-hasura-user-id": user.uid,
},
};
return admin
.auth()
.setCustomUserClaims(user.uid, customClaims)
.then(() => {
const metadataRef = admin.database().ref("metadata/" + user.uid);
return metadataRef.set({refreshTime: new Date().getTime()});
})
.catch((error) => {
console.log(error);
});
});

Step 4: Deploy the cloud function

Save the code and then go to function folder and run the following command:

➜ ~ firebase deploy --only functions

Final output:

Cloud Function Execution

Go to Firebase console there you can see the deployed function in the Functions section

Firebase Functions

Before leave the Firebase console, we need to do some more settings. Lets do that.

1. Add Rules

You can read about Firebase Database Rules here to understand read and write conditions that can be specified for the user. Go to the Realtime Database Rules section and update following rules. We need to define conditions for when data can be read by users.

{
"rules": {
"metadata": {
"$uid": {
".read": "auth != null && auth.uid == $uid"
}
}
}
}
Firebase Rules

2. Enable sign in method

We need to enable sign in method. In our case, we will have google sign in method. You can enable mutiple method also. Go to Authentication Sign In method section and enable Google.

3. Add app

Go to Project setting General section and add you iOS app. Once it done, download the Google-info.plist file and add it inside your Xcode project.

All done in the Firebase! 🙌. Let’s take a deep breath! 😜

Heroku app configuration variables setup

Go to Heroku console and tap on the app listed in the home page.

Heroku home page

Go to setting Reveal Config Vars section and add the following Hasura configurations key and value:

1. HASURA_GRAPHQL_JWT_SECRET

Key: HASURA_GRAPHQL_ADMIN_SECRET
Value: "YOUR ADMIN SECRET"

2. HASURA_GRAPHQL_JWT_SECRET

Key: HASURA_GRAPHQL_JWT_SECRET  
Value: {
“type”:”RS256",
“jwk_url”: “https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com",
“audience”:"YOUR FIREBASE PROJECT ID",
“issuer”: “https://securetoken.google.com/"YOUR FIREBASE PROJECT ID""
}

3. HASURA_GRAPHQL_UNAUTHORIZED_ROLE

Key: HASURA_GRAPHQL_UNAUTHORIZED_ROLE
Value: anonymous

Its look like this,

Heroku app config variables

All done in the Heroku! 🙌

Hasura app environment variables setup

We need to add JWT environment variable in the Hasura project dashboard. Go to hasura project settings and add new enviroment variable key HASURA_GRAPHQL_JWT_SECRET with value.

Key: HASURA_GRAPHQL_JWT_SECRET  
Value: {
“type”:”RS256",
“jwk_url”: “https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com",
“audience”:"YOUR FIREBASE PROJECT ID",
“issuer”: “https://securetoken.google.com/"YOUR FIREBASE PROJECT ID""
}

All done in the Hasura! 🙌

Hasura — Table Creation

We need to create table in the Data section. For example, I’m going to create a table called ‘social_media’ and add column as ‘app_name’ and ‘user_id’ and tap on the add table CTA.

Add new table
Table created

You can add some data in the table via Insert Row tab.

Sample data

Hasura — Setup Permission

Go to Permission tab and enter new role as user and anonymous.

For user role, we going to allow user to do insert, select and delete on the table. Go to Row Permission and select With custom check and there add the condition

{"user_id":{"_eq":"X-Hasura-User-Id"}}
User Role — Row Permission

Then go to Column Permission and select columns that you want to display for the authenticated user. Once row and column permission is done, save the permission.

User Role — Column Permission

For anonymous role, we going to allow anonymous user to select without any check.

Anonymour Role — Row and Column Permission

Integrate Firebase Auth in iOS app

Install pods in the Xcode project

pod 'Firebase/Core'
pod 'Firebase/Messaging'
pod 'Firebase/Auth'
pod 'GoogleSignIn'

Work on the some UI to add google sign in app and to list the data on the app.

Add the following code in the app delegate’s didFinishLaunchingWithOptions method.

let firebaseOptions = FirebaseOptions(contentsOfFile: Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist")!)
FirebaseApp.configure(options: firebaseOptions!)
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID

Add this following code in the google sign in button action.

GIDSignIn.sharedInstance()?.presentingViewController = self
GIDSignIn.sharedInstance().signIn()
GIDSignIn.sharedInstance()?.delegate = self

Once google authentication was successful, you need to call firebase sign in auth method.

Auth.auth().signIn(with: credential) { (authResult, error) inlet currentUser = Auth.auth().currentUser
currentUser?.getIDTokenForcingRefresh(true) { idToken, error inif let token = idToken{
print("Firebase JWT token: \(token)")
}}}

You can check in the firebase console whether user successfully signed into the firebase or not.

Firebase Users

Hasura — Authorization

Now, you must have your own JWT token and User UID. We can check directly the Hasura’s console whether we can able to fetch data from the table using this JWT token. Before that, we need to update the table’s sample data with this User UID.

Column updated with User UID

Add Authorization key in the Request Headers with Value as

Bearer "YOUR_FIREBASE_JWT_TOKEN"

Use the following query to fetch data.

query{
social_media{
app_name
}
}

Thats it. Run the console!

Woot! 🍻 You should buy a beer for me! 😜

Sample iOS app:

iOS app

You can refer the sample iOS app code in my GitHub Repo.

Follow me on LinkedIN

 iOS Developer @nfnlabs, Chennai. Here to share best practices learned through my experience. Reach me on https://www.linkedin.com/in/ashokkumar-b-26026913a/