Firebase authentication with AngularFire2 and Ionic

June 13, 2017, 10:00 am Categories:

Categories

AngularFire provides lots of useful features for connecting to and interacting with a Firebase backend which is pretty helpful when used in the context of an Ionic application.

Over the course of the following tutorial I'm going to concentrate on one of those features provided by AngularFire: Authentication.

We'll be building a very simple Ionic application that demonstrates how to log into a Firebase service using an e-mail/password authentication scheme:

Ionic application log-in form with email and password fields

The application will, thanks to methods supplied courtesy of AngularFire's handy authentication module, inform the user of any issues with the supplied login credentials:

Ionic application log-in form displaying unsuccessful log-in attempt

And where supplied passwords have been entered incorrectly the user is made aware of this fact:

Ionic application log-in form displaying failed password during log-in attempt

Simple but super helpful from a user experience perspective (and that is SO important when developing applications).

Ready to go?

Let's get started!

Laying the foundation

As with all things Ionic we start off by firing up our system command line utility and creating a project using the Ionic CLI:

ionic start angular-fire blank

Here we're simply creating a new project, using a blank template, called angular-fire (kind of catchy huh?)

Answer any prompts that the CLI might throw up while creating the project (such as asking your permission to install local plugins) and, once successfully completed, install AngularFire with the following command:

npm install firebase angularfire2 --save

When completed create the following service (which we'll use to manage all authentication related tasks for the project):

ionic g provider authenticata

With the structure for the project now in place we can turn our attention towards providing the necessary credentials for our Firebase account.

Setting the environment

Inside your angular-fire/src directory create an environments sub-directory which will be used to store your firebase account/project credentials in the following environment.ts file:

export const environment = {
   production: false,
   firebase : {
      apiKey              : "API-KEY-IS-ENTERED-HERE",
      authDomain          : "https://console.firebase.google.com/project/YOUR-PROJECT-NAME-HERE",
      databaseURL         : "https://YOUR-DATABASE-NAME-HERE.firebaseio.com/",
      projectId           : "",
      storageBucket       : "YOUR-STORAGE-BUCKET-NAME-HERE.appspot.com",
      messagingSenderId   : "YOUR-MESSAGING-SENDER-ID-HERE"
   }
};

You can find the necessary values for the above from your Firebase account.

If you're not sure how to find these within Firebase please visit this tutorial which will help guide you.

With those credentials now in place save the environment.ts file to the angular-fire/src/environments directory and proceed on to the next, and final, configuration for the project - setting up the application's root module.

Rooting your project

Within the angular-fire/src/app/app.module.ts file we need to import the different Firebase modules, environment configuration script and Authenticata service that the application will require and be making use of.

Edit this file so that it mirrors the following example:

import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { environment } from '../environments/environment';


import { AngularFireModule } from 'angularfire2';
import { AngularFireAuthModule } from 'angularfire2/auth';
import { AngularFireDatabaseModule }  from 'angularfire2/database';
import { AuthenticataProvider } from '../providers/authenticata/authenticata';


@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    BrowserModule,
    HttpModule,
    IonicModule.forRoot(MyApp),
    AngularFireModule.initializeApp(environment.firebase),
    AngularFireDatabaseModule,
    AngularFireAuthModule
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    AuthenticataProvider
  ]
})
export class AppModule {}

With those configurations in place we can now start to actually develop the authentication logic for the project, starting with the Authenticata service.

Authorising access

Drawing on AngularFire's Authentication module we're going to use the Authenticata service to provide the necessary methods for managing the following processes:

  • Logging in with e-mail and password values
  • Logging out of our Firebase account

Here's what the logic for the angular-fire/src/providers/authenticata.ts file will look like in full:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';

import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';


@Injectable()
export class AuthenticataProvider {

   public user                   : Observable;


   constructor(public http       : Http,
               private _ANGFIRE  : AngularFireAuth) 
   {
      this.user                  = this._ANGFIRE.authState;
   }




   loginWithEmailAndPassword(email: string, password: string) : Promise<any>
   {      
      return new Promise((resolve, reject) =>
      {
         this._ANGFIRE
         .auth
         .signInWithEmailAndPassword(email, password)
         .then((val : any) =>
         {
            resolve();
         })
         .catch((err : any) =>
         {
            reject(err);
         });
      });
   }




   logOut() : Promise<any>
   {
      return new Promise((resolve, reject) =>
      {
         this._ANGFIRE.auth.signOut()
         .then((data : any) => 
         {
            resolve(data);
         })
         .catch((error : any) =>
         {
            reject(error);
         });
      }); 
   }


}

In order to break this down so that we fully understand how the authentication process works we need to pay attention to the following areas:

  • Monitoring the application's authentication state
  • loginWithEmailAndPassword method
  • logOut method

Monitoring the application's authentication state

AngularFire's authentication module makes use of the authState object which provides an observable that can be used to monitor the authentication state of the application.

Towards the beginning of our script we import the following modules that will help with the monitoring of the authentication state:

import { Observable } from 'rxjs/Observable';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';

We then define a public accessible property of user, set to a type of Observable, which will subsequently be used within the page template to reference the application's authentication state:

public user                   : Observable;

The authentication state is then assigned to this property within the class constructor like so:

constructor(public http       : Http,
            private _ANGFIRE  : AngularFireAuth) 
{
   this.user                  = this._ANGFIRE.authState;
}

loginWithEmailAndPassword method

Here we simply use the signInWithEmailAndPassword method of the AngularFireAuth module to manage logging into our Firebase account with the required email and password credentials.

A promise is used to manage the returned result and, if our login attempt should prove to be unsuccessful, any failures are also returned back to the user:

loginWithEmailAndPassword(email: string, password: string) : Promise<any>
{
   return new Promise((resolve, reject) =>
   {
      this._ANGFIRE
      .auth
      .signInWithEmailAndPassword(email, password)
      .then((val : any) =>
      {
         resolve();
      })
      .catch((err : any) =>
      {
         var message    = err.message;
         reject(message);
      });
   });
}

logOut method

Logging out of the Firebase service is handled using the signOut method of the AngularFireAuth module, using a promise to manage the asychronous nature of the operation:

logOut() : Promise<any>
{
   return new Promise((resolve, reject) =>
   {
      this._ANGFIRE.auth.signOut()
      .then((data : any) => 
      {
         resolve(data);
      })
      .catch((error : any) =>
      {
         reject(error);
      });
   }); 
}

With the necessary logic in place for the Authenticata service all the remains now is to configure the HomePage class and template for our application.

The home page logic

The angular-fire/src/pages/home/home.ts file will be used to provide the following functionality:

  • Handle form validation for the page template using Angular's FormBuilder module
  • Implement Firebase authentication using the Authenticata service

The FormBuilder module is used within the class constructor to create an object with some (very) basic validation rules for the email and password template form fields like so:

this.form = this._FB.group({
   'email'        : ['', Validators.required],
   'password'     : ['', Validators.required]
});

The logIn method is, in essence, a wrapper for the Authenticata service's loginWithEmailAndPassword method and manages the following tasks:

  • Retrieves the successfully validated email and password values from the page template's form fields
  • Executes the loginWithEmailAndPasswordmethod of the Authenticata service
  • If the log-in attempt was successful the form fields are reset to a blank state with the form set to no longer be displayed on the page
logIn()
{
   let email      : any        = this.form.controls['email'].value,
       password   : any        = this.form.controls['password'].value;

   this._AUTH.loginWithEmailAndPassword(email, password)
   .then((auth : string) => 
   {
      this.form.reset();
      this.displayForm     = false;
      this.displayError    = '';
   })
   .catch((error) => 
   {
      this.displayError    = error.message;
   });
}

Finally, the logOut method, which acts as a wrapper around the logOut method for the Authenticata service, manages logging out from the Firebase service and re-enabling the log-in form within the page template:

logOut()
{
   this._AUTH.logOut()
   .then((val) => 
   {
      this.displayForm     = true;
   })
   .catch((error) => 
   {
      this.displayError    = error.message;
   });
}

With that covered the entire code for the angular-fire/src/pages/home/home.ts file is as follows:

import { Component } from '@angular/core';
import { NavController, Platform } from 'ionic-angular';
import { AuthenticataProvider } from '../../providers/authenticata/authenticata';
import {
   FormBuilder,
   FormGroup, 
   Validators } from '@angular/forms';


@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

   public form                  : FormGroup;
   public displayForm           : boolean        = true;
   public displayError          : string;


   constructor(public navCtrl   : NavController,
               private _FB      : FormBuilder,
               private _PLAT    : Platform,
               public _AUTH     : AuthorisaProvider) 
   {
      this.form = this._FB.group({
         'email'        : ['', Validators.required],
         'password'     : ['', Validators.required]
      });
   }




   logIn()
   {

      let email      : any        = this.form.controls['email'].value,
          password   : any        = this.form.controls['password'].value;

      this._AUTH.loginWithEmailAndPassword(email, password)
      .then((auth : string) => 
      {
         this.form.reset();
         this.displayForm     = false;
         this.displayError    = '';
      })
      .catch((error) => 
      {
         this.displayError    = error.message;
      });
   }




   logOut()
   {
      this._AUTH.logOut()
      .then((val) => 
      {
         this.displayForm     = true;
      })
      .catch((error) => 
      {
         this.displayError    = error.message;
      });
   }


}

All that remains, coding wise, is to display the template for the HomePage component.

Templating the application

The angular-fire/src/pages/home/home.html template will be used to manage the following front-end aspects of the project:

  • Conditionally manage, through using Angular's NgIf directive, the display of a log-in form
  • Use the FormBuilder object that was created in the component's TypeScript class to manage the log-in form and its fields
  • Manage the display of log-in errors
  • Conditionally display a log out button if the user has been successfully authenticated
  • Conditionally display the user's e-mail address

The following mark-up displays how each of the above is implemented and structured within the page template:

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic Fire
      <ion-buttons end>
         <button 
            *ngIf="!displayForm" 
            ion-button 
            color="primary" 
            (click)="logOut()">
            Log Out
         </button>
      </ion-buttons> 
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  

   <form 
      *ngIf="displayForm"
      [formGroup]="form" 
      (ngSubmit)="logIn()"> 
      <ion-list>
         <ion-item margin-bottom> 
            <ion-label>Your E-mail Address</ion-label> 
            <ion-input
               type="text"
               formControlName="email"></ion-input> 
         </ion-item>


         <ion-item margin-bottom>
            <ion-label>Your Password</ion-label> 
            <ion-input
               type="password"
               formControlName="password"></ion-input> 
         </ion-item>


         <button
            ion-button
            color="primary"
            text-center
            block [disabled]="!form.valid">Log In</button>
      </ion-list> 

      <p>{{ displayError }}</p>
   </form>



   <div *ngIf="!displayForm">
      <h1 *ngIf="_AUTH.user | async">Welcome {{ (_AUTH.user | async)?.email }}!</h1>
      <p>Logged in bro!</p>
   </div>

</ion-content>

Now all we need to do is run our application in the system browser with the following command:

ionic serve

Which, if all has been coded correctly, should display the following form:

Ionic application log-in form with email and password fields

Upon successful authentication you should be greeted with a screen akin to the following:

Ionic application successful login with AngularFire

In summary

As you can see authenticating Firebase access is incredibly simple thanks to AngularFire's Authentication module.

In the above tutorial we've only covered using the signInWithEmailAndPassword method but there are additional options for logging in using an OAuth flow through providers such as Twitter, Github and Facebook for example.

Hopefully you've found the above tutorial useful and, if so, please feel free to share your comments, thoughts and suggestions in the comments area below.

Please note that the e-book advertised below does NOT cover Firebase or AngularFire but I will be working on an Ionic/Firebase related e-book shortly.

If you're interested in learning more please sign up to my FREE mailing list where you can receive updates on current/forthcoming e-books and blog articles.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top