Hasura + Heroku + Firebase — Firebase Authentication and Hasura Authorization to an iOS app
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:
- Hasura — Hasura account creation and project console setup
- Heroku — Heroku account creation and app setup with configurations
- Firebase — Project setup and Deploying cloud function
- Hasura — Table creation and setting up user permission
- 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:
When you tap on the Launch Console CTA, it redirects to the projects 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 😅.
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 console:
Now, we are going to continue the heroku’s database creation. Tap on the ‘Create Database’ CTA.
It will create a new app in Heroku dashboard with Postgres database for our projects and linked to hasura.
Woot! 🍻 Heroku database was connected to Hasura.
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:
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:
Go to Firebase console there you can see the deployed function in the Functions section
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"
}
}
}
}
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.
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,
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.
You can add some data in the table via Insert Row tab.
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"}}
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.
For anonymous role, we going to allow anonymous user to select without any check.
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.
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.
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:
You can refer the sample iOS app code in my GitHub Repo.
Follow me on LinkedIN