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.
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
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:
Firebase is quickly growing to become the most popular mobile app back-end platform.
Steps to integrate Phone Authentication with Ionic App
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
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.
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.
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
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 :-
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
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
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 :-
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
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.
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.
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 !
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.
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?