Home Firebase
Category:

Firebase

Building Phone Verification or Two Factor Authentication(2FA) is complicated and time-consuming. I had to spend around a month building one by myself. Even if we can build it in-house, there could be many issues such as deliverability, security flaws, etc., because we are not experts in that domain. How about using an API and implement 2FA into your app in just 15 minutes?

Twilio Verify

It’s an API from Twilio that solves complex development challenges of 2FA so you can focus on core business functionalities.

Overview

1. Send OTP

OTP – One Time Password

You can use any server side service to trigger the Twilio Verify API. I used Firebase for this example. Twilio also has serverless functions that you can use for this.

Create your angular app. Add a component to capture the phone number.

Get the code from my Github repo: https://github.com/mliyanage/twilio-send

Call the Auth service OtpSend method and pass the phone number. Phone numbers should be validated against the E164 format. I’m optionally checking whether the phone number is already registered in the system by querying the user’s collection.
After calling the API, send the user to the OTP page (go to step 2)

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
import { UiService } from '../services/ui.service';
import isdcodes from '../../assets/isdcodes.json';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

  isProgressVisible: boolean;
  loginForm!: FormGroup;
  firebaseErrorMessage: string;
  isdCodelist: {dial_code:string, name:string}[] = isdcodes;

  constructor(private authService: AuthService, private router: Router, private uiService:UiService) {
    this.isProgressVisible = false;
    this.firebaseErrorMessage = '';
}

  ngOnInit(): void {
    this.loginForm = new FormGroup({
      'isdCodes': new FormControl('', [Validators.required]),
      'phone': new FormControl('', [Validators.required])
      
  });
  }

  login() {
    if (this.loginForm.invalid)
        return;

    const phoneNo = this.loginForm.value.isdCodes+this.loginForm.value.phone;
    //Validate E164 format
    let regexPhone = new RegExp(/^\+[1-9]\d{10,14}$/);
    if (!regexPhone.test(phoneNo)) 
    {
      this.uiService.showSnackBar("Invalid phone number",null,300);
      return;
    }

    this.isProgressVisible = true;

    this.authService.getUserByPhone(phoneNo).subscribe(
      (data) => {
        this.authService.otpSend(phoneNo).subscribe((res)=>{
          this.uiService.showSnackBar("Otp has been sent",null,300);  
          this.router.navigate(['/otp']);
        })
      },
      (err) => {
        this.isProgressVisible = false; 
        this.uiService.showSnackBar("User does not exists, please sign up",null,300);
      }
    );
   
}

}
Add a service to your angular app to invoke HTTP functions.
Here I have services for send OTP, Verify OTP, Sign up a new user, and get existing users by phone number.
I used Angular Material Snack-bar to show messages. There is another service called uiService for this. You can check out the complete code for that.

import { Injectable } from '@angular/core';
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';
import { Router } from '@angular/router';
import { UiService } from './ui.service';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment';
import { Observable } from 'rxjs';


@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private baseUrl = environment.baseUrl;
  userLoggedIn: boolean;


  constructor(private router: Router, private angularFirestore: AngularFirestore, private uiService: UiService, private http:HttpClient) {
        this.userLoggedIn = false;
  }

	getUserByPhone(phone: string):Observable<any> {
	  const phoneNo = phone.substring(1); //without + prefix
	  return this.angularFirestore.doc('users/' + phoneNo).snapshotChanges();
	}
	
	otpSend(phone: string): Observable<any> {
	 
	  return this.post("/otpSend",{"phone":phone})
	}
	
	otpVerificationCheck(otp: string): Observable<any> {
	  const phone = this.readFromLocal("phone");
	  return this.post("/otpVerificationCheck",{"phone":phone, "otp": otp})
	}

	signupUser(user: any): Promise<any> {
	      return this.angularFirestore.doc('/users/' + user.phone.substring(1))  
	      .set({
	          displayName: user.displayName,
	          phone: user.phone,
	      }).then((result)=>{
	        this.uiService.showSnackBar("You will get an OTP",null,300);
	        this.saveIntoLocal("phone",user.phone)
	      }).catch(error => {
	        this.uiService.showSnackBar("Sign up failed, try again later",null,300);
	  });
	}
}

Next, Cloud Functions to Send the OTP and Verify the OTP. To send, you have to use

Refer to the documentation for other languages like C#, PHP, Ruby, Python, Java, etc.

Here I have three functions:

otpSend – this will be called from the front-end to send an OTP to the user

otpVerificationCheck – this will be called from the front-end to verify the OTP entered by the user

onUserCreate – this is the CloudFirestore trigger that I have used to send an OTP when a new user is signed up. When a new document is created in the user’s collection, this function will be invoked. Sign-up functionality is not covered in this post. You can check the code from the Github repo.

const functions = require("firebase-functions");
const admin = require('firebase-admin');
const accountSid = functions.config().twilio.sid;
const authToken = functions.config().twilio.token;
const serviceId = functions.config().twilio.serviceid;
const client = require('twilio')(accountSid, authToken);
const cors = require('cors');

admin.initializeApp();

const db = admin.firestore();

//Send an OTP to new user
exports.onUserCreate = functions.firestore.document('users/{phone}').onCreate(async(snap, context)=>{
    const values = snap.data();
    //Send OTP
    await db.collection('message-log').add({description: `OTP has been sent to user to:${values.phone} `});
    client.verify.services(serviceId)
             .verifications
             .create({to: values.phone, channel: 'sms'})
             .then(verification => console.log(verification.status));

})

//Validate the OTP
exports.otpVerificationCheck = functions.https.onRequest(async (req, res) => { cors()(req, res, () => {
    // Check for POST request
    if(req.method !== "POST"){
        res.status(400).send('Please send a POST request');
        return;
    }
    const msgStatus = req.body;
    client.verify.services(serviceId)
      .verificationChecks
      .create({to: msgStatus.phone, code: msgStatus.otp})
      .then(verification_check => res.json({result: verification_check.status}));
      
  });
});

 //Send a new OTP
 exports.otpSend = functions.https.onRequest(async (req, res) => { cors()(req, res, () => {
    // Check for POST request
    if(req.method !== "POST"){
        res.status(400).send('Please send a POST request');
        return;
    }
    const request = req.body;
    const resp = client.verify.services(serviceId)
             .verifications
             .create({to: request.phone, channel: 'sms'})
             .then(otp => res.json({result: otp}));
            
 });
});
2. Verify OTP
Add a component to capture the OTP from the user.


import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Router } from '@angular/router';

import { AuthService } from '../services/auth.service';
import { UiService } from '../services/ui.service';

@Component({
  selector: 'app-otp',
  templateUrl: './otp.component.html',
  styleUrls: ['./otp.component.css']
})
export class OtpComponent implements OnInit {

  isProgressVisible: boolean;
  otpForm!: FormGroup;

  constructor(private authService: AuthService, private router: Router, private uiService:UiService) {
    this.isProgressVisible = false;
  
}

  ngOnInit(): void {
    this.otpForm = new FormGroup({
      'otpValue': new FormControl('', Validators.required)
  });
  }

  validateOTP(){
    this.isProgressVisible = true;
    this.authService.otpVerificationCheck(this.otpForm.value.otpValue).subscribe(
      (data) => {
        this.isProgressVisible = false; 
        this.router.navigate(['/home']);
      },
      (err) => {
        this.isProgressVisible = false; 
        this.uiService.showSnackBar("OTP Validation failed",null,300);
      }
    );
  }
}

Upon submit, call the otpVerificationCheck of the Auth service, and that will trigger the cloud function to invoke the Twilio verification check API to validate the OTP.
If it returns success, you can send the user to the restricted log-in area of the application. You have to implement Angular Auth guard for this.

0 comment
5 FacebookTwitterPinterestEmail

Build your startup and launch your MVP for FREE using Firebase as the back-end

If you are a first-time founder and coming from a non-technical background, you will face the challenge of setting up your IT infrastructure and how to deploy your app cost-effectively. You will be able to find developers to build your product, but still, you need to have servers and databases to host your application. What is the cheapest way to do this until you get traction and investors to fund your startup? Let’s take this hypothetical product that you will build is a marketplace app for local organic food vendors to sell their products online. Let’s call it FOODANIC.

Overview of the application

Food vendors can register their shops on Foodanic.com or using the mobile app. There is a one-month free trial period for vendors, and after that, they have to 50$ a month to use the platform.

Vendors can list their products.

When a customer makes a purchase, vendors will get a notification, and they have to make the item to be picked by the Foodanic delivery service. Simultaneously, the nearest delivery truck will get a message with the vendor and customer information.

For this, we will have to have one app for vendors, one for the delivery team, and one for customers. Customers also can use the foodanic.com website to order food.

What is the fundamental infrastructure needed for this app and your startup to provide its intended services?

Infrastructure requirements and solutions

  1. You need a Database to store your food vendors and customer information and other information like orders. You can use Cloud Firestore for this. Cloud Firestore Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud. Cloud Firestore is a cloud-hosted, NoSQL database that your iOS, Android, and web apps can access directly via native SDKs. Cloud Firestore is also available in native Node.js, Java, Python, Unity, C++, and Go SDKs, in addition to REST and RPC APIs. https://firebase.google.com/docs/firestore Before you start working on Cloud Firestore, learn about NoSQL data modeling. https://www.youtube.com/watch?v=lW7DWV2jST0&t=1s

2. You need some general-purpose storage to store images

Use Cloud Storage for Firebase. This is easy to use, cost-effective storage, and You can use Firebase SDKs to store images, audio, video, or other user-generated content. You can secure your files using Firebase Security rules

  1. You need an Identity service for authenticating users for your app using email, phone number, Google, Facebook, etc.

    Use Firebase Authentication service. This provides back-end services, easy-to-use SDKs, and ready-made UI libraries to authenticate users to your app.
  1. Web hosting to host foodanic.com. Website is a front-end web app like React or Angular web app.

Use Firebase Hosting. This is production-grade web content hosting for developers. With a single command, you can quickly deploy web apps and serve both static and dynamic content to a global CDN

  1. Sending Emails and SMS to users

You can use a service like Twilio for both emails and SMS, or you can find a local service for SMS.

  1. Sending push notifications

Use Firebase Cloud Messaging (FCM) to send notifications for Android, IOS and Web clients.

Also, you can use FCM from Firebase console to send out promotional notifications for your user base and different user segments.

7. Credit card payments

Check out – hey’s respond to apple and Apple approves Hey email app, but the fight’s not over

You can use some local provide depending on the country or use Stipe if available in your country. Do your research on payment options such as in-app purchases. It depends on the service you are providing. There are many controversies around Apple pushing companies to use their in-app purchases instead of using credit card payment. If you plan to have any paid services, do thorough research before implementing the feature.

8. You need some email hosting providers to host your mailboxes for your company ex: info@foodanic.com.

There are so many cheap email hosting provides, and it’s just a matter of finding a service provider to match your budget. In the beginning, you can use a free email forwarder like https://improvmx.com/

  1. You probably need an accounting system to manage your finance.

You can use Wave, and it’s free. https://www.waveapps.com/pricing

  1. Office tools such as Word processing and spreadsheets

Use Google docs, Sheets, and Google drive. You get 15GB of storage for free. Just remember, Google can see your content in the Drive.

Organize your Drive and provide appropriate access for the team.

Example:

11. Track user behavior

Use Google Analytics for Firebase. The SDK automatically captures certain key events and user properties, and you can define your own custom events to measure the things that uniquely matter to your business.

  1. It would help if you had a way of tracking app crashes and understand issues to improve user experience.

Use Firebase Crashlytics. Firebase Crashlytics is a lightweight, realtime crash reporter that helps you track, prioritize, and fix stability issues that erode your app quality.

  1. How to deploy test builds to internal testers quickly without going through App Store and Google play or sending files manually?

Use Firebase App Distribution. This makes distributing your apps to trusted testers painless. By getting your apps onto testers’ devices quickly, you can get feedback early and often.

  1. How to experiment with different features and make better decisions?

Of course, you can ask your friends and focus groups, but the best way to find out is to run AB tests. Firebase A/B Testing helps you optimize your app experience by making it easy to run, analyze, and scale product and marketing experiments.

  1. Shareable links for app promotions and ads

Use Firebase Dynamic Links. With Dynamic Links, your users get the best available experience for the platform they open your link. If a user opens a Dynamic Link on iOS or Android, they can be taken directly to the linked content in your native app. If a user opens the same Dynamic Link in a desktop browser, they can be taken to the equivalent content on your website.

  1. Sometimes we need to change the behavior and appearance of your app without publishing an app update.

Use the Firebase Remote Config. It is a cloud service that lets you change the behavior and appearance of your app without requiring users to download an app update.

17. Source code maintenacne and version control

Github or GitLab

  1. Build Automation

Use Codemagic https://codemagic.io/

  1. Scheduled jobs, triggers, HTTP APIs

You can use Firebase Cloud Functions to schedule any back-end process or trigger an event based on a Firestore database operation. For example, you can send a notification to the user when a new document is added to a Fire Store collection.

In addition, you can create cloud functions as HTTP endpoints if in case if you want to expose an API to your app or to a third party.

What about data security, privacy, and compliance?

Security in the cloud is a shared responsibility between the cloud provider and the customer. Every cloud providers have a shared responsibility model when it comes to security and compliance. They guarantee compliance for the infrastructure, and then you have to make sure your application and your company is adhering to the compliance requirements.

Be aware of your privacy and compliance requirements before choosing any cloud storage solution. Read this for Firebase: https://firebase.google.com/support/privacy

If you are building healthcare-related apps, be aware of mandatory compliances like HIPAA

https://cloud.google.com/security/compliance/hipaa/#covered-products

Check this for more information: https://cloud.google.com/security/compliance

You would need to do more research on this related to your application and the company. This is an example of building a HIPAA compliance chat app

https://virgilsecurity.com/blog/hipaa-firebase

Check out this white papper

Where would my data store and processed?

You should be aware of Data storage and processing locations. For example, some services run only in the US, such as Firebase Hosting, Realtime Database, and Authentication

https://firebase.google.com/docs/projects/locations

Pricing

Firebase services are billed based on its usage, and until you reach a considerable user base you can run all the services for free.

https://firebase.google.com/pricing

https://firebase.google.com/docs/firestore/quotas

Setup a usage alert to avoid unpredicted billing.

You need to check pricing for other services like payment gateway, SMS and emails.

Drawbacks and limitations of Firebase

  • Vendor lock-in. Everything is dependent on Firebase SDK; therefore, you will have to rewrite the whole app if you choose to change your back-end later on.
  • Data migration problems. You have to write programs to import/export data from Firestore to and in JSON format.
  • Limited querying capabilities. You will have very less query capabilities on the Firebase console.
  • Will not work in countries where Google is not allowed
  • Cloud Function has some delay; it could be up to 10 seconds. They are microservices and they need to be started when an event occurs, so there is some warm up time for Cloud Functions.
  • Free tier has limitations on services like Analytics, concurrent connections, Google maps
  • Be aware of Cloud Firestore limits such as document write frequency and size limits. https://firebase.google.com/docs/firestore/quotas
  • Understand Firestore query limitations https://firebase.google.com/docs/firestore/query-data/queries

Data encryption

Firebase services encrypt data in transit using HTTPS and logically isolate customer data.

In addition, several Firebase services also encrypt their data at rest:

  • Cloud Firestore
  • Cloud Functions for Firebase
  • Cloud Storage for Firebase
  • Firebase Authentication
  • Firebase Cloud Messaging
  • Firebase Realtime Database
  • Firebase Test Lab

Setting up Firebase environment

Do some thinking before you create your environments. You would typically need Development, Testing, and Production environments. Or make it simple to keep one environment for Dev and test and one for Production. Name your environments appropriately to avoid accidental changes or deletes. Provide appropriate access. You can provide access to your staff based on roles using user and permission options. Use the principle of least privilege. The principle of least privilege works by allowing only enough access to perform the required job.

Release management

You have to develop a release flow of the apps for internal tests, TestFligt/ Internal Beta, and then production. Below is a simplified flow of app releases.

Use Firebase App Distribution to send releases quickly without any review process. Also, you can use Crashlytics to monitor issues and app crashes in each build.

Once you decide to release the app to the production, you need to go through the app review process for both Google and Apple. Then release the app internally as a beta or TestFlight and do a high level test, and finally, publish.

Branching strategy for GIT

After your app goes live, you will have to work in parallel to fix issues and develop new features. If you don’t have a clear branching strategy, you will end up in a mess. Therefore, do some brainstorming with your team and come up with a plan. This is a helpful article on this.

https://nvie.com/posts/a-successful-git-branching-model/

https://docs.microsoft.com/en-us/azure/devops/repos/git/git-branching-guidance?view=azure-devops

Be prepared to go through the hurdles of getting App Store approval

Allocate some time to do your research on how to get your App approved by Google Play and App Store. Specifically, for AppStore, they have stringent guidelines. So do your studies and get everything ready before you submit your app for approval.

https://developer.apple.com/app-store/review/guidelines/

https://developer.android.com/distribute/best-practices/launch/launch-checklist

  • There are specific guidelines for the medical and health apps in the iOS App Store.

Read this blog post about the new points related to the guideline.

If your company is a single owner or a proprietary establishment, then you will not be able to put your company name in the App Store. You will not be allowed to create an organization account in App Store. And you have to use an individual developer account.

0 comment
0 FacebookTwitterPinterestEmail