Search
  • Seiji Ralph Villafranca

Securing your Angular App w/ Firebase Authentication

Application development nowadays are very demanding, being in the world of dev industry, more and mode ideas and features are emerging and it is being required to be delivered in a shorter amount of time and we as the developers of our holy grail app, there are numerous aspects we need to worry in developing our application some of these are the security/authentication, database and storage and analytics and monitoring, yes! these are just some things that we need to consider and by just thinking of it is just a huge pain in our lives!


Well, Firebase saves the day! we don't actually need to develop these features for our application as Firebase has got our back.


So what is Firebase?

Firebase is a platform by Google that helps us on our mobile and web applications, it offers several services such as Authentication, Realtime Database, Storage, Analytics, Hosting and Serverless deployments and even machine learning. it is a very powerful platform that will help us develop our application in a shorter period of time and less worry about some things we need for our development.


In this tutorial we will tackle one of the offered services by Firebase and this is security and Authentication, we will configure our firebase authentication step by step with our Angular application by integrating a simple login page that will be managed by Firebase Authentication.


Configuring our Firebase Project.

The first thing we need to is to create our Firebase project, go to https://firebase.google.com


we need an account for us to create a project, we can us our google account for us to have a faster registration process, after successful creation of account, we will create a project under our profile.


we will start by naming our project, in my example above, I have chosen to name my project as firebase auth.


We will see the Enable Google Analytics page after setting our name, we will just enable this for our project.


we will set our own account for Google analytics, we will not tackle this as this is another service offered by firebase.


And after minutes of setup, our project is now ready, we will proceed to our project dashboard and explore the features of our authentication service.


in the left panel menu click on the Authentication and click the Get started button to setup our authentication feature.

under the Sign-in method tab, we will enable the Google mail and Email Password sign in for our application, this will allow users to Sign In using their Google account.


after enabling our Sign-in methods, we will go to our project settings, we will see that it is stated that there are no apps in our project, we will add a web app project to have our configuration.


we will see the generated configuration of our firebase project, we will only need the firebase config portion as this will be used in our Angular Application.


And our Firebase project is now ready to use!


Developing our Angular Application

Now, we will proceed on developing our angular application, I'm assuming here that you already have a scaffold angular app using angular cli but if you don't have, we will just execute the following command.

ng new {project-name}

now we have our angular application, Firebase has already include libraries that are ready to use for us to easily integrate our Firebase project with Angular. we will now install @angular/fire and firebase by executing the following command.

npm install @angular/fire firebase --save

@angular/fire - includes AngularFIreAuth service that we need to access functions for login and registration


firebase - will be used to instantiate our Google Auth Provider.


for aesthetics or UI purposes we will also install ngx-toastr for notifications, we will execute the following command

npm install ngx-toastr --save

now we have installed our required dependencies in our Angular app, we will use our firebase configuration earlier and place it on our app.module.ts with Angular Fire


import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AngularFireModule } from "@angular/fire";
import { AngularFireAuthModule } from "@angular/fire/auth";
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ToastrModule } from 'ngx-toastr';

var config = {
 apiKey: "{apiKey}",
 authDomain: "{authDomain}",
 projectId: "{projectId}",
 storageBucket: "{storageBucket}",
 messagingSenderId: "{messagingSenderId}",
 appId: "{appId}",
 measurementId: "{measurementId}"
};
@NgModule({
 declarations: [
    AppComponent
  ],
 imports: [
 BrowserModule,
 AngularFireModule.initializeApp(config),
 AngularFireAuthModule,
 AppRoutingModule,
 BrowserAnimationsModule,
 ToastrModule.forRoot(),
  ],
 providers: [],
 bootstrap: [AppComponent]
})
export class AppModule { }

 

we can see here that we have imported our AngularFireModule.initializeaApp() using our project configuration as parameters, we will be configuring authentication so we have also imported AngularFireAuthModule for us to use Angular authentication service.


next thing we need is we would wat to replace the content of our app.component.html with router-outlet.

<router-outlet></router-outlet>

now we will create our auth service under the core folder, let's execute the following command to generate our auth service.

ng g s core/services/auth

now in our auth.service.ts file we will place the following code

import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import firebase from 'firebase/app';
import { Router } from '@angular/router';
@Injectable({
 providedIn: 'root'
})
export class AuthService {
 user;
 constructor(public fireAuth: AngularFireAuth, private router: Router) {
 this.fireAuth.authState.subscribe(user => {
    if (user){
        this.user = user;
        localStorage.setItem('user', JSON.stringify(this.user));
        this.router.navigate(["/home"]);
    } else {
        localStorage.setItem('user', null);
        this.router.navigate(["/login"]);
    }
   })
}

 login(email: string, password: string): Promise<any> {
    return this.fireAuth.signInWithEmailAndPassword(email, password);
 }

 register(email: string, password: string): Promise<any> {
   return this.fireAuth.createUserWithEmailAndPassword(email, password)
 }

 loginWithGoogle(){
   return this.fireAuth.signInWithPopup(new 
    firebase.auth.GoogleAuthProvider())
 }

 logout(){
    return this.fireAuth.signOut();
 }

}


let us tackle the code one by one, first we have injected our AngularFIreAuth in our auth service, this allows us to access functions that will allow us to communicate with firebase authentication, the authState is an Observable that allows us to check if a valid user is logged in in our application, this will return the information of the user and we will place this as a string on local storage, we would also want to redirect the user to the home page if he/she is logged in.


login() - we will call the signInWithEmailAndPassword() function from fire auth, this will accept two paramters namely the email and password, this returns a promise.


register() - we will call the createUserWithEmailAndPassword() function from fire auth, this will also accep email and password as parameters for the user to be registered. This also returns a promise.


loginWithGoogle() - we will call the signInWithPopup of Fire auth and we will pass a new instance of Google Auth Provider


logout() - we will call the signOut() function to end the user session.


We now have our service that we will use on our login page, our next step is to create our login module and home module that will use our authentication service. let's create a login module, a login routing and a login component on our application let us execute the following commands:


Login Module

generate a login module with route

ng g m module/login --routing

generate a login component

ng g c login

in our login module we will place the following code

import { LoginComponent } from './login/login.component';
import { LoginRoutes } from './login.routing';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule} from "@angular/forms";


@NgModule({
 declarations: [LoginComponent],
 imports: [
 CommonModule,
 LoginRoutes,
 FormsModule,
 ReactiveFormsModule
  ]
})
export class LoginModule { }


we have added FormsModule and ReactiveFormsModule as we will be using this for our login form.


and for our login-routing.ts we will declare LoginComponent as our base component for our Login Module


import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login/login.component';

const routes: Routes = [
  { path: "", component: LoginComponent },
];

export const LoginRoutes = RouterModule.forChild(routes);


In our login.component.html, we will place the following html code to create our login page.



 <div class="main">
   <p class="sign">Sign in</p>
   <form class="form1" [formGroup]="form">
     <input class="un " formControlName="email" type="text" 
     placeholder="Email"/>
     <input class="pass" formControlName="password" type="password" 
     placeholder="Password"/>

     <ng-container *ngIf="page === 'login'">
          <a class="submit" (click)="login()">Sign in</a>
          <br><br>

          <div (click)="loginWithGoogle()" class="btn" role="button" 
          style="text-transform:none">
               <img width="20px" style="margin-bottom:0px; margin- 
               right:5px" alt="Google sign-in" src="https://upload.
               wikimedia.org/wikipedia/commons/thumb/5
               /53/Google_%22G%22_Logo.svg/512px- 
                Google_%22G%22_Logo.svg.png" />
              Login with Google
         </div>

     </ng-container>

     <ng-container *ngIf="page === 'register'">
         <a class="submit" (click)="register()">Register</a>
     </ng-container>
     <br><br>
     <div class="link" *ngIf="page === 'register'" (click)="page = 
     'login'">Sign In</div>
      <div class="link" *ngIf="page === 'login'" (click)="page = 
     'register'">Register</div>
  </form>
</div>

 

we can see here that we have created a form element in our page that has a formGroup property, in this case we need to have a form builder that will be used to bind with our form, in our login.component.ts we will place the following code.


import { AuthService } from './../../../core/services/auth.service';
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { Router } from '@angular/router';

@Component({
 selector: 'app-login',
 templateUrl: './login.component.html',
 styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
 form: FormGroup;
 page="login";
 constructor(
 private authService: AuthService,
 private fb : FormBuilder,
 private toastr: ToastrService,
 private router: Router) { }

 ngOnInit() {
   this.initForm();
 }

 initForm() {
   this.form = this.fb.group({
      email: [''],
      password: ['']
    });
 }


 login() {
    this.authService.login(this.form.controls['email'].value, 
    this.form.controls['password'].value).then((data) => {
       this.router.navigate(["/home"]);
    }).catch((err) => {
       this.toastr.error(err.message, "Error");
   });

  }

 register() {
    this.authService.register(this.form.controls['email'].value, 
    this.form.controls['password'].value).then((data) => {
       this.toastr.success("Successfully registered", "Success");
    }).catch((err) => {
       this.toastr.error(err.message, "Error");
   });

  }

 loginWithGoogle() {
    this.authService.loginWithGoogle().then((data) => {
       this.router.navigate(["/home"]);
     }).catch((err) => {
        this.toastr.error(err.message, "Error");
   });
  }

}


in the example code above, we can see that we have injected our AuthService in our login component, we have also injected a formBuilder to create our form group instance that will handle our form controls.


login() - calls authService.login() which returns a promise, this will redirect to our home page if username and password is valid, else it will return and error with a detailed message provided.


register() - calls authService.register() which returns a promise, this will be successful if the credentials has met the requirements, we might want to ask if we can add additional information for the user on registration, the answer is yes but we need the firebase database for us to store the additional information.


loginWithGoogle() - calls authService.loginWithGoogle() which also returns a promise, this will first project a popup that allows us to login with our Gmail Account.


Home Module

generate a home module with route

ng g m module/home --routing

generate a home component

ng g c home

in our home-routing.ts we will use the Home Component as our base component for our Home Module

import { HomeComponent } from './home/home.component';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  {
 path: "", component: HomeComponent
   },
];

export const HomeRoutes = RouterModule.forChild(routes);


and in our home page will create our sample home page with a logout button.

<div class="programmer">
</div>
<div class="details">
    <div>
       <h2>Hooray!! you are logged in!</h2>
    </div>
    <br><br>
    <div>
       <a class="signout" (click)="logout()">Sign Out</a>
    </div>
</div>


and in our home.component.ts we will place the following code with the logout application

import { AuthService } from './../../../core/services/auth.service';
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

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

 constructor( private authService: AuthService, private router: Router) { }

 ngOnInit() {
  }

 logout() {
      this.authService.logout().then(() => {
       localStorage.removeItem('user');
       this.router.navigate(['/login']);
    });
  }

}


as the user logouts we will remove the user information we stored on our local storage and redirect it on our login page.


and we have completely configured our Firebase Authentication with our Angular App, at this moment, we should have following folder structure on our application.

the only thing we need is to configure our routes in our app-routing.ts, we will use lazy loading for our modules.


import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  {
      path: "",
      redirectTo: "login",
      pathMatch: "full"
  },
  {
      path: "login", loadChildren: () => 
      import("./modules/login/login.module").then(m => m.LoginModule)
  },
  {
      path: "home", loadChildren: () => 
      import("./modules/home/home.module").then(m => m.HomeModule)
  }
];

@NgModule({
 imports: [RouterModule.forRoot(routes)],
 exports: [RouterModule]
})
export class AppRoutingModule { }



let us just also add a simple CSS for our login and home page to make our app look nicer!


in styles.scss we will place the following CSS code

// regular style toast
@import '~ngx-toastr/toastr';

body {
 font-family: 'Ubuntu', sans-serif;
}

.main {
 background-color: #FFFFFF;
 width: 400px;
 height: 400px;
 margin: 7em auto;
 border-radius: 1.5em;
 box-shadow: 0px 11px 35px 2px rgba(0, 0, 0, 0.14);
}

.sign {
 padding-top: 40px;
 color: rgb(20, 59, 149);
 font-family: 'Ubuntu', sans-serif;
 font-weight: bold;
 font-size: 23px;
 text-align: center;
}

.un {
width: 76%;
color: rgb(38, 50, 56);
font-weight: 700;
font-size: 14px;
letter-spacing: 1px;
background: rgba(136, 126, 126, 0.04);
padding: 10px 20px;
border: none;
border-radius: 20px;
outline: none;
box-sizing: border-box;
border: 2px solid rgba(0, 0, 0, 0.02);
margin-bottom: 50px;
margin-left: 46px;
text-align: center;
margin-bottom: 27px;
font-family: 'Ubuntu', sans-serif;
}

form.form1 {
 padding-top: 40px;
}

.pass {
 width: 76%;
color: rgb(38, 50, 56);
font-weight: 700;
font-size: 14px;
letter-spacing: 1px;
background: rgba(136, 126, 126, 0.04);
padding: 10px 20px;
border: none;
border-radius: 20px;
outline: none;
box-sizing: border-box;
border: 2px solid rgba(0, 0, 0, 0.02);
margin-bottom: 50px;
margin-left: 46px;
text-align: center;
margin-bottom: 27px;
font-family: 'Ubuntu', sans-serif;
}


.un:focus, .pass:focus {
 border: 2px solid rgba(0, 0, 0, 0.18) !important;

}

.submit {
 cursor: pointer;
 border-radius: 5em;
 color: #fff;
 background: linear-gradient(to right, rgb(34, 48, 170), rgb(22, 68, 125));
 border: 0;
 padding-left: 40px;
 padding-right: 40px;
 padding-bottom: 10px;
 padding-top: 10px;
 font-family: 'Ubuntu', sans-serif;
 margin-left: 35%;
 font-size: 13px;
 box-shadow: 0 0 20px 1px rgba(0, 0, 0, 0.04);
}

.signout {
 cursor: pointer;
 border-radius: 5em;
 color: #fff;
 background: linear-gradient(to right, rgb(34, 48, 170), rgb(22, 68, 125));
 border: 0;
 padding-left: 40px;
 padding-right: 40px;
 padding-bottom: 10px;
 padding-top: 10px;
 font-family: 'Ubuntu', sans-serif;
 margin-left: 25%;
 font-size: 13px;
 box-shadow: 0 0 20px 1px rgba(0, 0, 0, 0.04);
}

.forgot {
 text-shadow: 0px 0px 3px rgba(117, 117, 117, 0.12);
 color: #E1BEE7;
 padding-top: 15px;
 text-align: center;
}

a {
 text-shadow: 0px 0px 3px rgba(117, 117, 117, 0.12);
 color: #E1BEE7;
 text-decoration: none
}

.btn {
 width: 200px;
 border-style: solid;
 padding: 8px;
 margin: auto;
 text-align: center;
 border-width: 1px;
 border-radius: 20px;
 border-color: #9e9b9b;
 cursor: pointer;
}

.programmer {
 width: 300px;
 height: 300px;
 background: url("assets/images//programmer.gif");
 background-position: center;
 background-repeat: no-repeat;
 background-size: cover;
 display: flex;
 margin: 0;
 position: absolute;
 top: 50%;
 left: 50%;
 -ms-transform: translate(-50%, -50%);
 transform: translate(-50%, -50%);

}

.details {
 position: absolute;
 margin: 0;
 position: absolute;
 top: 70%;
 left: 50%;
 -ms-transform: translate(-50%, -50%);
 transform: translate(-50%, -50%);
}

.link {
 cursor: pointer;
 margin: auto;
 width: 200px;
 text-align: center;
 text-decoration: underline;
}

@media (max-width: 600px) {
 .main {
 border-radius: 0px;
  }
}




and now we are now ready to run our project locally, we will run the ng s command on our cli to serve our Angular application.


After successful compilation, we will now see our login page up and running!

we can logged in as a raw email and password with our application (Note* you must register first a new user credentials for this to work, all registered users can be seen under the user tab in firebase) or we can logged in using our Google Account. In this example I have used my google account to login and Voala! we are now redirected to our home page!


we can see the endpoints from google are called successfully from our application to allow us to use our Google credentials as our access.


we can now check under the applications tab that the user information of the logged in user has been stored in our local storage.


and that's it! we have configured our Angular application with authentication of Firebase. to have a look on the complete code you can check out my GitHub repository with the link below:


https://github.com/SeijiV13/angular-firebase-auth

hope you learned a lot from this tutorial, Cheers!




25 views0 comments

Recent Posts

See All

Follow me

© 2019 Seiji Villafranca
 

Call

0917-1368007

  • Facebook Clean
  • White LinkedIn Icon