Protecting Your App With Ionic Auth Guards Last update: 2017-04-04

Protecting Your App With Ionic Auth Guards

Recently I dig into authentication with Ionic a bit more and found a rather unrepresented topic that can actually help to secure your app really easy. I stumbled upon the Ionic Auth Guards while working on a new JWT Authentication course for the Ionic Academy.

The Ionic Auth Guards are the Ionic version of the Angular Navigation Guards. The guys from Thoughtram have a great post on this topic as well.

But Angular uses a different kind of routing (more of the classic URL routing style) than Ionic, which uses a simplified routing system targeted more towards mobile and the logic of different pages and viewcontroller.

Therefore we can not use the original Angular Navigation Guards but the Ionic version, which we will explore in this post.

Prerequisite

Learning Ionic can become overwhelming, I know that feeling. Is learning from tutorials and videos sometimes not enough for you? Then I got something for you.

If you want to learn Ionic with step-by-step video courses, hands-on training projects and a helpful community who has your back, then take a look at the Ionic Academy.

Join the Ionic Academy

The Logic

Ionic pages have different lifecycle events. If you want a complete overview about all events and the order in which they pop up, check out this post from Sani Yusuf which has a very good image of it as well.

The Ionic Auth Guards fall right into that category of lifecycle events and are called ionViewCanEnter and ionViewCanLeave and both will do exactly what they sound like: Either allowing navigation to a page or navigation away from a page. In detail these events are a good place to do the following:

ionViewCanEnter()

This event is fired before a page is loaded. No action of the page has taken place by now, and you can determine if the page is allowed to be presented. This means, you could check some conditions or in our case the authentication state of a user. If this function returns false, we need to make sure we handle this correctly as we normally assume every page will be pushed/displayed just fine.

ionViewCanLeave()

This is the counterpart to the before mentioned event and is fired right before a page tries to leave the screen. I thought about the usefulness of this event a bit more as in general you don’t want to forbid your user to leave a page! But in cases like inside a form where something needs to be filled out, catching the state of the form inside here could make sense. Anyway, you don’t want to completely forbid your user to leave a page, otherwise they will simply kill the app if they have “no way out”.

One note for authentication systems: Of course protecting pages is only one part of building authentication, you also have to take care of the backend logic of logging a user in and afterwards making authorized requests for example by sending an authorization header with your requests.

However, in our little example we will leave out the backend component and just fake it with a service that holds our current authentication state of the user.

Simple Auth Guard Example

As always, we start with a blank Ionic app. Additional we create a second page where we can navigate to, and also a provider which works as the manager for our user authentication state:

ionic start --v2 authGuardApp blank
cd authGuardApp
ionic g page Second
ionic g provider AuthService

First of all, make sure to add the new page and the provider to our module, so open the src/app.module.ts and insert:

import { AuthService } from './../providers/auth-service';
import { SecondPage } from './../pages/second/second';
import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';

import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

@NgModule({
  declarations: [
    MyApp,
    HomePage,
    SecondPage
  ],
  imports: [
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage,
    SecondPage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    AuthService
  ]
})
export class AppModule {}

As said before, our AuthService is just a dummy implementation without a real backend. However, we can represent the general behaviour of a regular auth service quite easily, and you could use this provider as a base for your own implementation.

Go ahead and insert into our src/providers/auth-service.ts:

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

@Injectable()
export class AuthService {

  private isLoggedIn = false;

  constructor() {}

  // Login a user
  // Normally make a server request and store
  // e.g. the auth token
  login() : void {
    this.isLoggedIn = true;
  }

  // Logout a user, destroy token and remove
  // every information related to a user
  logout() : void {
    this.isLoggedIn = false;
  }

  // Returns whether the user is currently authenticated
  // Could check if current token is still valid
  authenticated() : boolean {
    return this.isLoggedIn;
  }
}

We got everything we need for now, let’s use these functions.

We only need a very simple view for this example, just a few buttons and a title that indicates whether we are currently logged in.

Therefore, open the src/pages/home/home.html and insert:

<ion-header>
  <ion-navbar>
    <ion-title>
      Auth App
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
<h2 *ngIf="isAuthenticated()" text-center>User is logged in!</h2>
<h2 *ngIf="!isAuthenticated()" text-center>User is not logged in!</h2>

<button full ion-button color="primary" (click)="loginUser()">Login</button>
<button full ion-button color="danger" (click)="logoutUser()">Logout</button>
<button full ion-button color="secondary" (click)="nextPage()">Next Page</button>

</ion-content>

Nothing special so far, next the page with the functions. We need to hook up the actions to login and logout our user. We can simply do it through our authentication service, which is always a good way to do such a task.

Also, the state of the current user is only managed within that provider so we only need to look for changes there.

Finally, the function to push our next page is what more or less everything before was about. Instead of simply pushing a page onto our stack, we catch the possible error event and display an alert when it happens.

No additional check has to be made here, the rest is up to the following page to decide wheter someone can enter! Therefore, open the src/pages/home/home.ts and insert:

import { SecondPage } from './../second/second';
import { AuthService } from './../../providers/auth-service';
import { Component } from '@angular/core';

import { NavController, AlertController } from 'ionic-angular';

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

  constructor(public navCtrl: NavController, public authService: AuthService, public alertCtrl: AlertController) { }

  loginUser() {
    this.authService.login();
  }

  logoutUser() {
    this.authService.logout();
  }

  nextPage() {
    this.navCtrl.push(SecondPage).catch(err => {
      let alert = this.alertCtrl.create({
        title: 'No entry!',
        subTitle: 'You shall not pass',
        buttons: ['Okay']
      });
      alert.present();
    });
  }

  isAuthenticated() {
    return this.authService.authenticated();
  }
}

As said before, the last part is now up to the following page. Inside that page, we implement the ionViewCanEnter to prevent someone getting to this page if they are not authenticated.

In our case, the only check we need to perform is calling our authService again to see if a user is authenticated.

Overall you could also check for a token inside the storage and even return a promise inside this function, as the page transition event will wait for this function to finish!

It’s a really good place to check your authentication state, so open your src/pages/second/second.ts and insert:

import { AuthService } from './../../providers/auth-service';
import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';

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

  constructor(public navCtrl: NavController, public authService: AuthService) {}

  ionViewCanEnter() {
    return this.authService.authenticated();
  }
}

Now go ahead and play around with our easy Ionic Auth Guard example and work in your own backend calls and authentication logic inside the authService!

What next?

Of course this is only a basic example showing whats possible. The function to check our validation state should do a bit more depending on your system and probably return a promise.

If you want to use ionViewCanLeave is up to you, for some protected pages the ionViewCanEnter offers everything we need!

You can find a video version of this post below.

https://youtu.be/ugIhBC8tsQE

Happy Coding, Simon