How to use Angular Guards to protect your pages in Ionic apps
The job of an authentication guard is to fetch for the user’s authentication state and return true/false
depending on
whether or not there’s a logged in user.
If it returns true
the user will be able to navigate to that page if it returns false
we should redirect the user
somewhere else.
Open your terminal and use the CLI to create the guard:
ionic generate guard services/user/auth
NOTE: This is assuming you want your guard to be in that path, you can create it wherever you want.
Once it’s created, it’ll look something like this:
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor() {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean | Observable<boolean> | Promise<boolean> {
return true;
}
}
We’re going to use the onAuthStateChanged()
method, it connects to Firebase Authentication and listens to changes in
the user state to respond to them. You can read more about it in
Firebase Official Documentation.
However, the TL;DR is that it adds an observer for auth state changes, meaning that whenever an authentication change happens, it will trigger the observer and the function inside it will run again.
import { Injectable } from '@angular/core';
import {
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
Router,
} from '@angular/router';
import { Observable } from 'rxjs';
import { getAuth, onAuthStateChanged } from "firebase/auth";
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean | Observable<boolean> | Promise<boolean> {
return new Promise((resolve, reject) => {
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
resolve(true);
} else {
console.log('User is not logged in');
this.router.navigate(['/login']);
resolve(false);
}
});
});
}
}
We’re importing the 2 things we need from Firebase authentication:
import { getAuth, onAuthStateChanged } from 'firebase/auth';
The getAuth()
method helps us get the current authentication instance, and the onAuthStateChanged()
method checks if
there’s a user logged in.
If there is a user, we resolve the promise with true
, if there isn’t, we send back false
and use the router to
redirect the user to the login page.
Now that our Guard is created, we can call it from inside the app-routing.module.ts
file:
import { AuthGuard } from './services/user/auth.guard';
{
path: '',
loadChildren: () => import('./pages/home/home.module').then(m => m.HomePageModule),
canActivate: [AuthGuard],
},
{
path: 'home',
redirectTo: '',
pathMatch: 'full',
},
{
path: 'login',
loadChildren: () => import('./pages/login/login.module').then(m => m.LoginPageModule)
},
All you need to do is add the canActivate
property with the value of the AuthGuard
(or any other guard you create)
to the routes you want to be protected.