Getting Started With Firebase And Protecting Routes From Unauthorized Users in Angular

Hello Readers,

In this tutorial I am going to cover the following topics

  • Firebase
  • Authentication using Firebase
  • Protecting routes from unauthorized users and much more..

At the end of the tutorial, you will find the source code, so feel free to play with the code yourself.

I will divide this tutorial into 3 sections,

  • Setting up the Firebase
  • Fetching the data
  • Protecting routes.

Setting up the Firebase

  1. First visit the https://www.firebase.com/ then click on See our new Website and then at the right hand side top corner you will find Go to Console click on that and log in to your account or else visit https://console.firebase.google.com/ and login.

  2. Then from console click on create new project




Then after creating database click on authentication as shown below


As I want to create Login and sign up by email id and password I must enable it from sign-in method tab as shown below


Then click on web setup (top right corner),to get your configuration


Now it’s time to set the web configuration in index.html,open your index.html file and paste the script tag that you just got from Firebase as shown below,


So now all firebase setup portion is done, so now move to Angular to create the user. I am using in built authentication of firebase, for more information about it you can visit https://firebase.google.com/docs/auth/web/password-auth, there you can find doc about user management.

Angular Side

First I will generate one service and name it as user-auth.service, in which I created signupUser,signinUser,logout, etc.. 

  1. [code language=”typescript”]  
  2. import { Injectable } from '@angular/core';  
  3. import { User } from './user.interface';  
  4. import { Router } from '@angular/router';  
  5. import { Observable, Subject } from 'rxjs/Rx';  
  6. declare var firebase: any;  
  7. @Injectable()  
  8. export class UserAuthService {  
  9.   
  10.   constructor(private router: Router) { }  
  11.   signupUser(user: User) {  
  12.     firebase.auth().createUserWithEmailAndPassword(user.email, user.password)  
  13.       .catch(function (error) {  
  14.         console.log(error);  
  15.       });  
  16.   }  
  17.   logout() {  
  18.     firebase.auth().signOut();  
  19.     this.router.navigate(['/signin']);  
  20.   }  
  21.   signinUser(user: User) {  
  22.     firebase.auth().signInWithEmailAndPassword(user.email, user.password)  
  23.       .catch(function (error) {  
  24.         console.log(error);  
  25.         // ...  
  26.       });  
  27.   }  
  28.   isAuthenticated() {  
  29.     var user = firebase.auth().currentUser;  
  30.     if (user) {  
  31.       return true;  
  32.     }  
  33.     else {  
  34.       return false;  
  35.     }  
  36.   }  
  37.   userProfile() {  
  38.     var user = firebase.auth().currentUser;  
  39.     var name, email, photoUrl,password, uid, emailVerified;  
  40.     if (user != null) {  
  41.       //name = user.displayName;  
  42.       email = user.email;  
  43.       //password=user.password;  
  44.     return user;  
  45.       //photoUrl = user.photoURL;  
  46.       //emailVerified = user.emailVerified;  
  47.       //uid = user.uid;  
  48.     }  
  49.     else{  
  50.       return null;  
  51.     }  
  52.   }  
  53.   }  
  54. [/code]   

Here in the above code I had declared variable as firebase which is imported on index.html. Then methods like signinUser,signupUser,Logout methods are just copied from firebase docs. I also created one method isAuthenticated which will return true if user is authenticated and false if not authenticated, depending on this value we will display log out in header.component. Also I had created one interface of User which shown below. 

  1. [code language=”typescript”]  
  2. export interface User{  
  3.     email:string;  
  4.     password:string;  
  5.     confirmpassword:string;  
  6. }  
  7. [/code]   

Now that I created service for user management, now I will create header.component for routing through the application. Here I  used bootstrap for styling the application. For more details about how routing works you may read my other tutorials.( https://jinalshahblog.wordpress.com/2016/12/28/crud-in-angular2-part2/ )

Header.component.html 

  1. [code language=”html”]  
  2. <header>  
  3.     <nav class="navbar navbar-default">  
  4.         <div class="container-fluid">  
  5.             <ul class="nav navbar-nav">  
  6.                 <li><a routerLink="/signup">Sign Up</a></li>  
  7.                 <li><a routerLink="/signin">Sign In</a></li>  
  8.                 <li><a routerLink="/userProfile">ViewProfile</a></li>  
  9.             </ul>  
  10.             <ul class="nav navbar-nav navbar-right" *ngIf="isAuth()">  
  11.                 <li><a (click)="onLogout()" style="cursor: pointer;">Logout</a></li>  
  12.             </ul>  
  13.         </div>  
  14.     </nav>  
  15. </header>              
  16. [/code]   

 header.component.ts 

  1. [code language=”typescript”]  
  2. import { Component, OnInit } from '@angular/core';  
  3. import { UserAuthService } from './user-auth.service';  
  4. @Component({  
  5.   selector: 'app-header',  
  6.   templateUrl: './header.component.html',  
  7.   styleUrls: ['./header.component.css']  
  8. })  
  9. export class HeaderComponent implements OnInit {  
  10.   
  11.   constructor(private userauthService:UserAuthService) { }  
  12. isAuth() {  
  13.         return this.userauthService.isAuthenticated();  
  14.     }  
  15.   ngOnInit() {  
  16.   }  
  17. onLogout() {  
  18.   alert("LogOut Called");  
  19.         this.userauthService.logout();  
  20.     }  
  21. }  
  22. [/code]   

Here I  imported the service which I created previously. Look at the method isAuth() which is calling the isAuthenticated method of service which will return true if user is logged in or return false if user is not logged in and based on that result I am displaying the logout button of header.component.html as shown below. 

  1. [code language=”html”]  
  2. <ul class="nav navbar-nav navbar-right" *ngIf="isAuth()">  
  3.                 <li><a (click)="onLogout()" style="cursor: pointer;">Logout</a></li>  
  4.             </ul>  
  5. [/code]   

So far I covered how to set up firebase,user-auth service,headercomponent and etc..

In this tutorial I am showing data driven approach for signup and signin component.

Data Driven Approch

First I will create signup.component to create new user. As I am using data driven approach I need to import formbuilder,formgroup,validator,formcontrol from @angular/forms.

Signup.component 

  1. [code language=”html”]  
  2. <form [formGroup]="myForm" (ngSubmit)="onSignup()">  
  3.   <div class="form-group">  
  4.     <label for="email">E-Mail</label>  
  5.     <input formControlName="email" type="email" id="email" #email class="form-control">  
  6.     <span *ngIf="!email.pristine && email.errors != null && email.errors['noEmail']">Invalid mail address</span>  
  7.   </div>  
  8.   <div class="form-group">  
  9.     <label for="password">Password</label>  
  10.     <input formControlName="password" type="password" id="password" class="form-control">  
  11.   </div>  
  12.   <div class="form-group">  
  13.     <label for="confirm-password">Confirm Password</label>  
  14.     <input formControlName="confirmPassword" type="password" id="confirm-password" #confirmPassword class="form-control">  
  15.     <span *ngIf="!confirmPassword.pristine && confirmPassword.errors != null && confirmPassword.errors['passwordsNotMatch']">Passwords do not match</span>  
  16.   </div>  
  17.   <button type="submit" [disabled]="!myForm.valid" class="btn btn-primary">Sign Up</button>  
  18. </form>  
  19. [/code]   

Signup.component.ts 

  1. [code language=”typescript”]  
  2. import { Component, OnInit } from '@angular/core';  
  3. import { FormBuilder, FormGroup, Validators, FormControl } from "@angular/forms";  
  4. import { UserAuthService } from '../user-auth.service';  
  5. @Component({  
  6.   selector: 'app-signup',  
  7.   templateUrl: './signup.component.html',  
  8.   styleUrls: ['./signup.component.css']  
  9. })  
  10. export class SignupComponent implements OnInit {  
  11.  myForm: FormGroup;  
  12.     error = false;  
  13.     errorMessage = '';  
  14.    constructor(private fb: FormBuilder, private userauthService: UserAuthService) {}  
  15.   ngOnInit() {  
  16.   this.myForm = this.fb.group({  
  17.             email: ['', Validators.compose([  
  18.                 Validators.required,  
  19.                 this.isEmail  
  20.             ])],  
  21.             password: ['', Validators.required],  
  22.             confirmPassword: ['', Validators.compose([  
  23.                 Validators.required,  
  24.                 this.isEqualPassword.bind(this)  
  25.             ])],  
  26.         });  
  27.   }  
  28.   isEmail(control: FormControl): {[s: string]: boolean} {  
  29.         if (!control.value.match(/^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/)) {  
  30.             return {noEmail: true};  
  31.         }  
  32.     }  
  33.     isEqualPassword(control: FormControl): {[s: string]: boolean} {  
  34.         if (!this.myForm) {  
  35.             return {passwordsNotMatch: true};  
  36.         }  
  37.         if (control.value !== this.myForm.controls['password'].value) {  
  38.             return {passwordsNotMatch: true};  
  39.         }  
  40.     }  
  41.  onSignup() {  
  42.       this.userauthService.signupUser(this.myForm.value);  
  43.     }  
  44. }  
  45. [/code]   

Here in the above example I  used two different validations to show some example of how to use custom validations in Angular. Here I am checking email and both passwords and confirming whether the  password are the same or not. As shown in the above code you can use custom validations. In above example 2-3 key terms are important while using a data driven approach.

  1. [formGroup]=”myForm”
  2. FormBuilder
  3. Validators

And the most important thing to rember while using the data driven approach is to add ReactiveFormsModule in app.module.ts file as shown below otherwise it will give error of formGroup property of form tag. 

  1. [code language=”typescript”]  
  2. import { ReactiveFormsModule } from '@angular/forms';  
  3. @NgModule({  
  4. imports: [  
  5.     BrowserModule,    
  6.      ReactiveFormsModule,   
  7.     HttpModule,  
  8.     routing  
  9.      
  10.   ],  
  11.   providers: [UserAuthService,UserAuthGuardService]  
  12. })  
  13. [/code]   

So after adding everything correctly, your signup using firebase authentication is done. Now it’s time for Signin.component

Signin.component.html 

  1. [code language=”html”]  
  2. <h1>Sign In</h1>  
  3. <form [formGroup]="myForm" (ngSubmit)="onSignin()">  
  4.   <div class="form-group">  
  5.     <label for="email">E-Mail</label>  
  6.     <input formControlName="email" type="email" id="email" class="form-control">  
  7.   </div>  
  8.   <div class="input-group">  
  9.     <label for="password">Password</label>  
  10.     <input formControlName="password" type="password" id="password" class="form-control">  
  11.   </div>  
  12.   <button type="submit" [disabled]="!myForm.valid" class="btn btn-primary">Sign In</button>  
  13. </form>  
  14. [/code]   

Signin.component.ts 

  1. [code language=”typescript”]  
  2. import { Component, OnInit } from '@angular/core';  
  3. import { FormBuilder, FormGroup, Validators } from "@angular/forms";  
  4. import { UserAuthService } from '../user-auth.service';  
  5. @Component({  
  6.   selector: 'app-signin',  
  7.   templateUrl: './signin.component.html',  
  8.   styleUrls: ['./signin.component.css']  
  9. })  
  10. export class SigninComponent implements OnInit {  
  11. myForm: FormGroup;  
  12.     error = false;  
  13.     errorMessage = '';  
  14.     constructor(private fb: FormBuilder, private userauthService: UserAuthService) {}  
  15.     onSignin() {  
  16.       this.userauthService.signinUser(this.myForm.value);  
  17.     }  
  18. ngOnInit():any {  
  19.         this.myForm = this.fb.group({  
  20.             email: ['', Validators.required],  
  21.             password: ['', Validators.required],  
  22.         });  
  23.     }  
  24. }  
  25. [/code]   

Here in signin.component I am only using required validator for email and password. onSignIn I am passing the the value of myForm i.e. whole form because myForm contains email and password only.

Now as signin and signup is done, now it’s time for viewprofile of logged In User. But before displaying user’s profile ,I had to check whether the user is authenticated to access the profile page or not.(i.e. user is only able to see his/her profile once he/she is logged in. Before log in they can’t visit viewprofile page.) To do so I am creating new service named user-auth-guard. In simple language I am creating routing guard so that anybody can’t access the restricted pages without logging in. There are two ways for doing it. One is previously used for the log out button and the other one is to use canActivate property of routing.

User-auth-guard.service.ts 

  1. [code language=”typescript”]  
  2. import { Injectable } from '@angular/core';  
  3. import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';  
  4. import { Observable } from 'rxjs/Rx';  
  5. import { UserAuthService } from './user-auth.service';  
  6. @Injectable()  
  7. export class UserAuthGuardService {  
  8.   constructor(private _data: UserAuthService) { }  
  9.   canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {  
  10.     return this._data.isAuthenticated();  
  11.   }  
  12. }  
  13. [/code]   

To create guard for router I am overriding canActivate method which is imported from CanActivate package of @angular/router ,which takes two arguments activatedroutesnapshot and routerstatesnapshot and returns Boolean value, so on this method I am returning result of isAuthenticated method of userAuthService ,which will return true if user is logged in false otherwise. And in app.routing.ts ,which contains array for routing I am using canActivate property of routing as shown below.

App.routing.ts 

  1. [code language=”typescript”]  
  2. import { RouterModule, Routes } from "@angular/router";  
  3. import { SignupComponent } from './users/signup.component';  
  4. import { UsersComponent } from './users/users.component';  
  5. import { SigninComponent } from './users/signin.component';  
  6. import { UserAuthGuardService } from './user-auth-guard.service';  
  7. const APP_ROUTES: Routes = [  
  8.     {path: '', redirectTo: '/signup', pathMatch: 'full'},  
  9.     {path: 'signup', component: SignupComponent},  
  10.     {path: 'userProfile', component: UsersComponent ,canActivate:[UserAuthGuardService] },  
  11.     {path: 'signin', component: SigninComponent}  
  12. ];  
  13. export const routing = RouterModule.forRoot(APP_ROUTES);  
  14. [/code]   

Here in above array app_routes I can visit signup.component,signin.component without logging in but I can’t visit users.component without logging in, because I had used canActivate property. You can apply this canActivate property on any component which you want to be protected from unauthorized access.

Summary

We covered a lot in this tutorial!! Let’s just summarize it.

  • Starting with firebase
  • Using inbuilt authentication of firebase
  • Route guard
  • Fetching and inserting data to firebase

You can download the soureCode here.

Note

To run the demo correctly don’t forget to add web configuration setting in index.html and also don’t forget to run npm install to download all the dependencies.