Firebase Phone Authentication in Ionic 5 Angular Apps

Firebase Phone Authentication in Ionic 5 Angular Apps

In this tutorial, we will learn how to integrate Firebase Phone Authentication with Ionic Angular Application. This method can make use of ReCaptcha, but there is option to make the captcha invisible (Users don’t need to verify the captcha).We will use the?angular/fire?library to use the firebase features in the example App.

Why Phone Authentication?

Phone Authentication?is one of the most used methods to verify the user in just a few seconds. This method is more important as we are not very good at maintaining passwords for various sites — the only good friend we have is our smartphone. By exchanging a Code between the provider and the user — UX is improved a lot — even better than the social logins which not everybody is comfortable using.

Firebase provides an easy way to integrate this service with our application and websites. In this example, we will use it on an Ionic Angular Application but concepts work with most of the Web applications.

OTP has come..!!

Before going further we can have a look at Ionic and Firebase in a little more detail, which can help you to implement several more features very easily. You can skip the next sections if you already know about Firebase and Ionic features.

Ionic Framework

The Ionic framework has been around for 5+ years and has been very popular among developers for its ease of usage over Swift / Java. Also in Ionic, you get to keep a single source code for both Android and iOS apps. What more can a developer ask for!

Ionic 5 is the latest version (at the time of writing this post) of Ionic and is much more reliable and robust than previous versions.

There are several ways of Authentication in Ionic 5 apps

  • Social logins?— Social logins are a popular and easy way of authentication in mobile apps. You must have seen Google, Facebook, Instagram logins in almost all the modern apps. Social logins are easy to use and more reliable for quick integrations.
  • Create your own back-end?— You can create your own back-end in Node.js, Go, Django or Ruby-on-rails, and connect your app authentication to your own back-end. This method is favoured by developers who need full control over user authentication. But this method is the most time taking one as well.
  • Back-end as a Service (BaaS) —?You?can use pre-built BaaS platforms which allows easy integration of authentication in your apps. Basically, these platforms provide you with a ready-made back-end, so you don’t have to make one on your own. Firebase, Parse,?Back4App?are some BaaS platforms.
  • Firebase?is the most popular among these for mobile apps, which we’ll study in the next section.

Firebase

Firebase is a Backend-as-a-Service (BaaS) platform. It started as a?YC11 startup?and grew up into a next-generation app-development platform on Google Cloud Platform. It is getting popular by the day because of the ease of integration and the variety of functionalities available on it.

A lot of quick integrations are available with Firebase. Some of these are listed below:

  • Real-time database
  • Email and?Phone Authentication
  • Social logins
  • In-app messages
  • Push notifications
  • Analytics
  • Crashlytics
  • Remote config

Firebase is quickly growing to become the most popular mobile app back-end platform.

Steps to integrate Phone Authentication with Ionic App

  1. Create a?Firebase Project?and enable Phone Authentication
  2. Create a new Ionic application (For more details visit?this blog)
  3. Integrate the Firebase project with the Ionic app
  4. Prepare the UI for Phone Auth
  5. Phone auth without ReCaptcha
  6. Phone auth with ReCaptcha
  7. Test the Phone authentication in Android device and web

Let’s jump into the Firebase Phone Auth example .

Step 1: Create a Firebase Project and Enable the Phone Authentication

First, we have to create the Firebase Project. For that, you have to go to?Firebase console?and create a new Project

Create a new Firebase project from Firebase console

After that, you will be asked for the Project name and some other details about the project and you are good to go.

Next, go to the Authentication menu in Sidebar and enable the Phone Authentication option as shown in the above image.

Enable Firebase Phone Authentication from the console

Now we have to use the Firebase config to integrate it with the Ionic Application. For that go to Project Overview > Project Settings and scroll down you will get the firebase Config.

Obtaining config from Firebase console, required for initializing the app with Firebase

You can copy this Firebase config for now. Later on will use them in the Ionic app to initialize the Firebase project.

Note: With latest update in Dec 2020, Firebase config does not include?databaseURL for new projects. This can be an issue as several of the Firebase dependent libraries have not updated themselves to accept this change. In case you don’t see databaseURL in Firebase config, create the information yourself by writing?databaseURL: <YOUR-PROJECT-ID>.firebaseio.com

Step 2: Create an Ionic Angular Application

To create an Ionic Angular Project you just have to run one command and that's it ! Rest of the things are handled by the Ionic-CLI. Run the below command in you terminal.

$ ionic start phone-auth blank --type=angular --cordova
        

The?--type=angular told the CLI to create an?Angular?app, not a?React?app. And?--cordova tells the CLI to integrate Cordova support by default. You can also use?--capacitor instead of Cordova.

( My environment for this blog is — Node 14.x, Ionic 5.5, Angular 11.x, NPM 7.x, Cordova 10.0 )

This will create an empty ionic project in the working directory of your pc and now you are done with all of the basic requirements to create an Ionic phone auth application. For more details on creating a new Ionic app from scratch, check out our blogs on Ionic Apps?here.

Step 3: Connect Firebase with Ionic Angular app

First, we have to initialize the Firebase Project in our Ionic application by using the firebase config that we have copied earlier. Before that install some of the packages for firebase.


$ npm i @angular/fire firebase
        
Note : The above command adds the?AngularFireModule (6.1.4)?and?firebase (8.6.1)?in our Ionic Project. This is the latest Firebase version as of May 2021. Older versions can have slightly different syntax.


Now paste the Firebase config in?environment.ts which is copied from Firebase console as per Step 1. Replace the *** with your own values.


export const environment = {
    production: false,
    firebaseConfig : {
       apiKey: "***********************",
       authDomain: "**********************",
       databaseURL: "***********************",
       projectId: "****************",
       storageBucket: "*******************",
       messagingSenderId: "**********",
       appId: "*******************************"
    }
};
        

Initialize Firebase in?app.module.ts using the above configuration. Carefully plug the following code in the required spots in?app.module.ts


...

import firebase from 'firebase/app'; 
import { environment } from 'src/environments/environment';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFirestoreModule } from '@angular/fire/firestore';
@NgModule({  
 ..., 
 imports: [    
  ...,
  AngularFireModule.initializeApp(environment.firebaseConfig), 
  AngularFireAuthModule,    
  AngularFirestoreModule  
 ],  
 ...
})
export class AppModule {}
        

Using?initializeApp?method of?AngularFireModule?package, we have initialized the Firebase project. This uses the config defined in?environments.ts page.

And we have also initialized the?AngularAuthModule, which provides methods like? createUserWithEmailAndPassword,?signInWithPhoneNumber, and many more.

Step 4 — Prepare the UI for Phone Auth

Preparing the UI is not an exact requirement. You can create the UI anyway you want. Here’s just how I did it.

HTML


<ion-content class="ion-no-padding"
	  <div id="sign-in-button"></div>
	

	  <div class="main">
	    <ion-card no-margin>
	      <ion-card-content>
	        <ion-row class="row">
	          <div class="fire-logo">
	            <img src="../../assets/fire.png" class="img-logo">
	            <ion-text class="ion-padding">
	              <h2 class="ion-no-margin ion-margin-vertical ion-text-center">Welcome to Ionic 5 Firebase Phone Auth</h2>
	            </ion-text>
	          </div>
	        </ion-row>
	        <ion-grid class="phoneAuthGrid">
	          <ion-row>
	            <ion-col size="4">
	              <ion-select class="phoneCountry" value="brown" okText="Okay" cancelText="Dismiss"
	                (ionChange)="countryCodeChange($event)" [value]="CountryCode">
	                <ion-select-option *ngFor="let country of CountryJson" value={{country.dial_code}}>
	                  {{country.dial_code + ' ' + country.name}}</ion-select-option>
	              </ion-select>
	            </ion-col>
	            <ion-col size="8">
	              <ion-input clearInput type="test" placeholder="Your Contact Number" [(ngModel)]="PhoneNo"
	                class="input ion-padding-horizontal" clear-input="true"></ion-input>
	            </ion-col>
	          </ion-row>
	          <ion-row>
	            <ion-col>
	              <ion-button expand="block" (click)="signinWithPhoneNumber($event)" color="undefined"
	                class="btn-transition">
	                Sign in with Phone number</ion-button>
	            </ion-col>
	          </ion-row>
	        </ion-grid>
	

	      </ion-card-content>
	    </ion-card>
</div>        

SCSS


   .main 
	  height: 100vh;
	  display: flex;
	  flex-direction: column;
	  justify-content: center;
	}
	@media screen and (min-width: 767px) {
	  ion-card {
	    width: 600px;
	    margin: auto;
	  }
	}
	ion-card {
	  --background: #fff;
	  box-shadow: none;
	  -webkit-box-shadow: none;
	  overflow: scroll;
	}
	.input {
	  background-color: rgb(240, 240, 240);
	  border: 1px solid rgb(210, 210, 210);
	  border-radius: 9px;
	  font-size: 0.9em !important;
	}
	.otpinput {
	  letter-spacing: 30px;
	  -webkit-padding-end: 0;
	  --padding-end: 0;
	  font-size: 30px;
	  border: none;
	  background: white;
	}
	.white {
	  color: white;
	}
	.OTP-border {
	  ion-col {
	    div {
	      border-bottom: 1px solid;
	    }
	  }
	}
	

	.small {
	  font-size: 13px;
	  a {
	    text-decoration: unset !important;
	  }
	}
	.button-color {
	  background-color: var(--ion-color-mytheme);
	}
	.logo {
	  width: 1.25em !important;
	}
	.grid {
	  height: 100vh;
	  display: flex;
	  flex-direction: column;
	  justify-content: center;
	}
	.row {
	  display: flex;
	  flex-direction: row;
	  justify-content: center;
	}
	.img-logo {
	  height: 120px;
	  width: 120px;
	}
	.fire-logo {
	  display: flex;
	  flex-direction: column;
	  justify-content: center;
	  align-items: center;
	  padding-bottom: 30px;
	}
	.bold {
	  font-weight: bold;
	}
	.block {
	  display: block;
	}
	.transition {
	  background: linear-gradient(to right, #f57c00 14%, #ffca00 96%);
	}
	.btn-color {
	  color: #ffa000;
	}
	.error {
	  color: red;
	  text-align: center;
	  display: block;
	  font-weight: bold;
	}
	

	.invoice-box {
	  max-width: 800px;
	  margin: auto;
	  padding: 30px;
	  border: 1px solid #eee;
	  box-shadow: 0 0 10px rgba(0, 0, 0, .15);
	  font-size: 16px;
	  line-height: 24px;
	  font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
	  color: #555;
	}
	

	.invoice-box table {
	  width: 100%;
	  line-height: inherit;
	  text-align: left;
	}
	

	.invoice-box table td {
	  padding: 5px;
	  vertical-align: top;
	}
	

	.invoice-box table tr td:nth-child(2) {
	  text-align: right;
	}
	

	.invoice-box table tr.top table td {
	  padding-bottom: 20px;
	}
	.btn-transition {
	  background: linear-gradient(to right, #f57c00 14%, #ffca00 96%);
	}
	

	.input {
	  background-color: rgb(240, 240, 240);
	  border: 1px solid rgb(210, 210, 210);
	  border-radius: 9px;
	  font-size: 0.9em !important;
	}
	.phoneCountry {
	  border: 1px solid gainsboro;
	  border-radius: 3px;
	  margin-left: 2px;
	}
	.phoneAuthGrid {
	  border: 1px solid #ccc;
	  margin: 0 7px;
	  border-radius: 3px;
	}
	.invoice-box table tr.top table td.title {
	  font-size: 45px;
	  line-height: 45px;
	  color: #333;
	}
	

	.invoice-box table tr.information table td {
	  padding-bottom: 40px;
	}
	

	.invoice-box table tr.heading td {
	  background: #eee;
	  border-bottom: 1px solid #ddd;
	  font-weight: bold;
	}
	

	.invoice-box table tr.details td {
	  padding-bottom: 20px;
	}
	

	.invoice-box table tr.item td{
	  border-bottom: 1px solid #eee;
	}
	

	.invoice-box table tr.item.last td {
	  border-bottom: none;
	}
	

	.invoice-box table tr.total td:nth-child(2) {
	  border-top: 2px solid #eee;
	  font-weight: bold;
	}
	

	@media only screen and (max-width: 600px) {
	  .invoice-box table tr.top table td {
	      width: 100%;
	      display: block;
	      text-align: center;
	  }
	  
	  .invoice-box table tr.information table td {
	      width: 100%;
	      display: block;
	      text-align: center;
	  }
	}
	

	/** RTL **/
	.rtl {
	  direction: rtl;
	  font-family: Tahoma, 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
	}
	

	.rtl table {
	  text-align: right;
	}
	

	.rtl table tr td:nth-child(2) {
	  text-align: left;
	}        

The UI will look like this

Phone auth in Ionic using Firebase — UI

Add country data

Also, for our dropdown we shall add a JSON containing country names, phone codes, and country codes, so our dropdown can work nicely. Here’s a sample of the JSON. If your country is missing in this, just add the required information. You can find a complete JSON?here. Add this information also in?environment.ts

CountryJson: [

{ name: 'Afghanistan', dial_code: '+93', code: 'AF' },
{ name: 'Albania', dial_code: '+35', code: 'AL' },
{ name: 'Algeria', dial_code: '+213', code: 'DZ' },
{ name: 'AmericanSamoa', dial_code: '+1 684', code: 'AS' },
{ name: 'Andorra', dial_code: '+376', code: 'AD' },
{ name: 'Angola', dial_code: '+244', code: 'AO' },
{ name: 'Anguilla', dial_code: '+1 264', code: 'AI' },
{ name: 'Antigua and Barbuda', dial_code: '+1268', code: 'AG' },
{ name: 'Argentina', dial_code: '+54', code: 'AR' },
{ name: 'Armenia', dial_code: '+374', code: 'AM' },
{ name: 'Aruba', dial_code: '+297', code: 'AW' },
....
]        

Step 5— Phone auth without ReCaptcha

In this step, developers have two options to make the Phone authentication flow work :-

  • Do not show a Captcha or ReCaptcha to make the flow smoother (meant for phone or web apps)
  • Show Captcha or ReCaptcha for better security (applicable for web apps only)

Implement Phone auth without Captcha/ReCaptcha

We will start with writing the logic for auto-validating Captcha/ReCaptcha and verifying the phone number. Flow will be

  • Create logic to handle user phone number, alerts and handle responses (home.page.ts)
  • Create an auth service which runs the firebase phone auth methods, and return response (auth-service.service.ts)

Let’s start with?home.page.ts


import { Component } from '@angular/core'
import { AlertController } from '@ionic/angular';
import { AuthServiceService } from '../services/auth-service.service';
import firebase from 'firebase/app';
import { environment } from '../../environments/environment';
@Component({
 selector: 'app-home',
 templateUrl: 'home.page.html',
 styleUrls: ['home.page.scss'],
})

export class HomePage {
  CountryJson = environment.CountryJson;
  OTP: string = '';
  Code: any;
  PhoneNo: any;
  CountryCode: any = '+91';
  showOTPInput: boolean = false;
  OTPmessage: string = 'An OTP is sent to your number. You should receive it in 15 s'
  recaptchaVerifier: firebase.auth.RecaptchaVerifier;
  confirmationResult: any;

  constructor(
	    private alertController: AlertController,
	    private authService: AuthServiceService
  ) { }
	

	

	  async ionViewDidEnter() {
	    this.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
	      size: 'invisible',
	      callback: (response) => {
	

	      },
	      'expired-callback': () => {
	      }
	    });
	  } 

	  ionViewDidLoad() {
	    this.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
	      size: 'invisible',
	      callback: (response) => {
	

	      },
	      'expired-callback': () => {
	      }
	    });
	  }
	

	  countryCodeChange($event) {
	    this.CountryCode = $event.detail.value;
	  }
	  // Button event after the nmber is entered and button is clicked
	  signinWithPhoneNumber($event) {
	    console.log('country', this.recaptchaVerifier);
	

	    if (this.PhoneNo && this.CountryCode) {
	      this.authService.signInWithPhoneNumber(this.recaptchaVerifier, this.CountryCode + this.PhoneNo).then(
	        success => {
	          this.OtpVerification();
	        }
	      );
	    }
	  } 

	  async showSuccess() {
	    const alert = await this.alertController.create({
	      header: 'Success',
	      buttons: [
	        {
	          text: 'Ok',
	          handler: (res) => {
	            alert.dismiss();
	          }
	        }
	      ]
	    });
	    alert.present();
	  } 

	  async OtpVerification() {
	    const alert = await this.alertController.create({
	      header: 'Enter OTP',
	      backdropDismiss: false,
	      inputs: [
	        {
	          name: 'otp',
	          type: 'text',
	          placeholder: 'Enter your otp',
	        }
	      ],
	      buttons: [{
	        text: 'Enter',
	        handler: (res) => {
	          this.authService.enterVerificationCode(res.otp).then(
	            userData => {
	              this.showSuccess();
	              console.log(userData);
	            }
	          );
	        }
	      }
	      ]
	    });
	    await alert.present();
	  }
 };        

Here

  • When we navigate to the Home page, The?Window object is set with the ReCaptcha using?new firebase.auth.RecaptchaVerifier(‘sign-in-button’)
  • sign-in-button is the HTML Id for the ReCaptcha in Home page. You can apple required CSS to the captcha as well.
  • You can see that ReCaptcha is actually rendered invisible here, by using the?‘size’: invisible?card.
  • We have created the ReCaptcha for validation of the user and we will pass the ReCaptcha reference and the phone number?( like with country code +1)?(const?appVerifier = this.recaptchaVerifier)?to the?signInWithPhoneNumber method defined under?AngularFireAuth.
  • Apply all this logic under button click event using method?signinWithPhoneNumber as shown in above Gist.

Create auth service

We pass the input phone number and appVerifier (i.e. ReCaptcha) to the? signInWithPhoneNumber function that is defined in?authService?file. You can generate the service file using?ionic g service auth-service command.

import { Injectable } from '@angular/core'
import { AngularFireAuth } from '@angular/fire/auth';
import firebase from 'firebase/app';
	

@Injectable({
  providedIn: 'root'
})

export class AuthServiceService {
  confirmationResult: firebase.auth.ConfirmationResult;
	
  constructor(private fireAuth: AngularFireAuth) { }
	

  public signInWithPhoneNumber(recaptchaVerifier, phoneNumber) {
	 return new Promise<any>((resolve, reject) => {
	

  	 this.fireAuth.signInWithPhoneNumber(phoneNumber, recaptchaVerifier)
  	 .then((confirmationResult) => {
  	     this.confirmationResult = confirmationResult;
  	     resolve(confirmationResult);
  	  }).catch((error) => {
  	     console.log(error);
  	     reject('SMS not sent');
  	  });
  	  });
  }

  public async enterVerificationCode(code) {
  	 return new Promise<any>((resolve, reject) => {
  	     this.confirmationResult.confirm(code).then(async (result) => {
  	        console.log(result);
  	        const user = result.user;
  	        resolve(user);
  	     }).catch((error) => {
  	        reject(error.message);
  	     });
  	
  	    });
  }
};        

this.fireAuth.auth.signInWithPhoneNumber?will give the verification Id in response (confirmationResult), shown in below figure :-

Response from firebase server after passing phone number and ReCaptcha verifier

Verifying OTP

As shown in above gists, the?OtpVerification method of?home.page.ts handles the OTP and sends it to auth service’s?enterVerificationCode method, which then verifies the OTP.

Step 6 — Phone auth with ReCaptcha (Preferred for web Apps)

The only change in this approach is we make the ReCaptcha visible. This give more smoother UX for phone apps users.

You must have noticed in previous section when you create the ReCaptcha using?firebase.auth.RecaptchaVerifier,?this class method takes 2 arguments

  • Id:- the id of the HTML container and
  • Options:- This options takes the size and callbacks (callback and expired callback)

Now to make the ReCaptcha visible, we simply pass?visible to the size option in the Firebase auth verifier method


this.recaptchaVerifier = new firebase.auth.
  RecaptchaVerifier('recaptcha-container', {
  size: 'visible',
  callback: (response) => {},
 'expired-callback': () => {}
});
        

In this approach, first the user will validate the Captcha/ReCaptcha manually, and only then OTP is sent to the user’s phone and?confirmationResult response is sent to the app by Firebase server. Now user can verify OTP is similar way as before.

ReCaptcha verification for Firebase Phone Authentication on localhost

Step 7— Testing on Device and Web

Note?: We can authenticate various users using the phone auth of Firebase, but after a limit Firebase starts charging according to the number of users.


Firebase Phone Authentication — Users’ list who are authenticated using Phone Authentication

Testing on Web

Testing on web is very simple, as you can test the phone auth simply on?ionic serve itself.

Testing on Android

To test on Android, build the application by running the following commands (for Cordova)


$ ionic cordova platform add android
$ ionic cordova build android
$ ionic cordova run android // Keep device connected
        

Conclusion

We have seen how we can authenticate users using Phone authentication in Firebase, in both phone and web apps. You can add more options?(like Facebook, Google, Twitter logins and many more)?to authenticate users using Firebase by visiting our?Blog Section. Now you are all ready to make your awesome application and add some new features to it.

Happy Coding !

Alok Prakash

Software Engineer

2 年

I always try to stay away with SMS authentication and use only to verify phone number. You cannot change the template of the SMS. Google Sign-in is best.

Harish Patidar

JavaScript | TypeScript | React | Single-Spa | Redux | Angular | Webpack | IONIC | Node | Unit Testing | MongoDB | Cypress

2 年

I did few years back same things but it wasn’t supported for iOS devices. Now it is working for iOS as well? Have you tested it?

回复

要查看或添加评论,请登录

Vaibhav Gehani的更多文章

社区洞察

其他会员也浏览了