Firebase Phone Authentication

Signing up users with a phone number adds certain degree of trust or confidence to an app. In this lesson, we are going to use the new phone authentication paradigm from Firebase in our Angular 4 app. At this time, phone auth is not supported in AngularFire, so we will use the firebase JavaScript SDK directly. Phone auth can also be used to link accounts, providing an effective solution for two-factor authentication.

Configuring the reCAPTCHA Widget in Angular

Firebase requires users to use reCAPTCHA to prevent abusive use of the API. You can also implement an invisible reCAPTCHA, but we will be using the visible version in this example.

visible recaptcha for firebase phone login angular

visible recaptcha for firebase phone login angular

Injecting the Window Object

You will need to make a reference to the Window object, which represents the DOM. It is considered a bad practice to modify `window` directly inside a component - the same goes for all global browser objects. Angular apps can also run on mobile and desktop platforms (which don't have a window), so a better alternative is to inject the window as a service.

Generate the service with `ng g service window`

import { Injectable } from '@angular/core';

@Injectable()
export class WindowService {

  get windowRef() {
    return window
  }

}

Phone Login Component

phone auth sms text confirmation

phone auth sms text confirmation

ng g component phone-login

Now we need to collect the user’s phone number. The number must be submitted in E.164 format, which looks like `+19495555555` for U.S. numbers.

In order keep values free of validation errors, I am breaking the from into four separate parts and creating a `PhoneNumber` class. Then I use a getter to combine the form values into a single string in E164 format.

PhoneNumber class

export class PhoneNumber {
  country: string;
  area: string;
  prefix: string;
  line: string;

  // format phone numbers as E.164
  get e164() {
    const num = this.country + this.area + this.prefix + this.line
    return `+${num}`
  }

}

After the the confirmation text is sent, we display another form field for the user to enter the confirmation. Here’s a breakdown of the process step-by-step

  • User verifies reCAPTCHA
  • User submits their phone number.
  • Firebase sends SMS text and returns a confirmation object.
  • User verifies SMS code and the auth state is updated.
result of successful Firebase phone auth

result of successful Firebase phone auth

phone-login.component.ts

import { Component, OnInit } from '@angular/core';
import { WindowService } from '../window.service';
import * as firebase from 'firebase';


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

  windowRef: any;

  phoneNumber = new PhoneNumber()

  verificationCode: string;

  user: any;

  constructor(private win: WindowService) { }

  ngOnInit() {
    this.windowRef = this.win.windowRef
    this.windowRef.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container')

    this.windowRef.recaptchaVerifier.render()
  }


  sendLoginCode() {

    const appVerifier = this.windowRef.recaptchaVerifier;

    const num = this.phoneNumber.e164;

    firebase.auth().signInWithPhoneNumber(num, appVerifier)
            .then(result => {

                this.windowRef.confirmationResult = result;

            })
            .catch( error => console.log(error) );

  }

  verifyLoginCode() {
    this.windowRef.confirmationResult
                  .confirm(this.verificationCode)
                  .then( result => {

                    this.user = result.user;

    })
    .catch( error => console.log(error, "Incorrect code entered?"));
  }


}

phone-login.component.html

In the HTML template, we trigger the various stages of the auth login with button clicks. The phone number object and the verification code are tracked with ngModel.

<div [hidden]="user">
  <h1>Sign In with Your Phone Number</h1>

  <label for="phone">Phone Number</label><br>
  <input type="text" [(ngModel)]="phoneNumber.country"  class="input" placeholder="1"    maxlength="2">
  <input type="text" [(ngModel)]="phoneNumber.area"     class="input" placeholder="949"  maxlength="3">
  <input type="text" [(ngModel)]="phoneNumber.prefix"   class="input" placeholder="555"  maxlength="3">
  <input type="text" [(ngModel)]="phoneNumber.line"     class="input" placeholder="5555" maxlength="4">

  <div id="recaptcha-container"></div>

  <button (click)="sendLoginCode()">SMS Text Login Code</button>

  <div *ngIf="windowRef.confirmationResult">
    <hr>
    <label for="code">Enter your Verification Code Here</label><br>
    <input type="text" name="code" [(ngModel)]="verificationCode">

    <button (click)="verifyLoginCode()">Verify</button>
  </div>

</div>

<div *ngIf="user">
  You have successfully logged in with your phone number!

  UserId: {{ user?.uid }}

</div>

Q&A Chat