Learn More

Everything you need to know about Firebase – Part 1

Chris Burton
Sep 15

This is part one of a series where we'll dive into Firebase and all the building blocks it provides to easily develop apps.

I’ve lost count of how many times I’ve come up with an idea for an app, get excited for it, start building it out only to abandon it part way through and add it to the graveyard of unfinished projects. Thankfully, with Google’s Firebase platform the effort from idea to app is greatly reduced.

If you’ve never heard of Firebase before I highly recommend checking it out. Firebase gives us all the building blocks needed to create mobile and web applications. My favourite thing about Firebase is its ease of use (no this blog isn’t sponsored by Firebase – I just LOVE IT!).

Throughout this series, I’ll show you how we can create a fully functional web-app deployed and ready to be used, all within a few hours of coding. A lot of work can go into creating complex and secure APIs for our projects, but Firebase takes care of a lot of these issues for us – Firebase becomes our backend.

The main features I’ll be going over in this series include:

  • Authentication
  • Firestore Database
  • Storage
  • Cloud Functions
  • Hosting

Github link to the repo: https://github.com/CBurton1/firebase-firefighters

Background

The app we are going to be building is a fire reporting app. Our app has a few requirements that Firebase will help us with:

 

  • Sign up & login firefighters
  • Must be able to upload a profile photo
  • Allow unauthenticated users to report new fires
  • Unauthenticated users cannot access any data besides being able to report a fire
  • Alert firefighters of new fires
  • Firefighters need to be notified in real time

Setup

Before we get started, there are a few additional tools we’ll be using to speed up our development

To get started with Angular, you can follow their setup guide here: https://angular.io/guide/setup-local

Once we have the Angular CLI installed on our system, we can get started with our project setup.

To create a new project with the angular CLI, run the following command:

ng new firebase-fighters --routing=true --style=scss

This will create a new Angular project and give us some presets for routing and using scss for our styles.

ng add @angular/material
ng add @angular/fire

These commands will add Angular Material (used for some nice looking components) and Angular Fire (an Angular Wrapper for the Firebase SDK).

Now that our project is set up, we’re going to use the Angular CLI to create our login module.

ng g module login --routing=true --module=app
ng g component login --module=login

We’ll need to update app-routing.module.ts to include our new login route. The file should look like this:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
 
const routes: Routes = [
 {
   path: "login",
   loadChildren: () => import("./pages/login/login.module").then(m => m.LoginModule),
 }
];
 
@NgModule({
 imports: [RouterModule.forRoot(routes)],
 exports: [RouterModule]
})
export class AppRoutingModule { }

So we now have an Angular Application setup with a login route, it’s time for us to set up Firebase!

Head to https://console.firebase.google.com/ and click the “Add Project” button. The setup is pretty straightforward. Once you create the project, we need to add our Web App to Firebase in order to get the credentials needed to connect our code to Firebase.

Add a new Web App to our Firebase project and get the config.

The config should look something like this:

 const firebase: {
   apiKey: "AIzaSyCoVhppoG-qa8GSzUl5DWIDOUQr0IjO6lo",
   authDomain: "fir-firefighter-adec0.firebaseapp.com",
   projectId: "fir-firefighter-adec0",
   storageBucket: "fir-firefighter-adec0.appspot.com",
   messagingSenderId: "388980493334",
   appId: "1:388980493334:web:1558d00f423b87325eb937",
   measurementId: "G-EPVBMHLBFS"
 }

Let’s add this config to our Angular Environment files so that we can use it inside our app.

Inside our app.module.ts, we can use the Angular Fire Module and the initializeApp function to initialize Firebase with the config from our environment file.

Our file should look something like this:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
 
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { LoginModule } from './pages/login/login.module';
import { AngularFireModule } from '@angular/fire';
import { environment } from 'src/environments/environment';
 
@NgModule({
 declarations: [
   AppComponent
 ],
 imports: [
   BrowserModule,
   AppRoutingModule,
   BrowserAnimationsModule,
   LoginModule,
   AngularFireModule.initializeApp(environment.firebase)
 ],
 providers: [],
 bootstrap: [AppComponent]
})
export class AppModule { }

We now have our codebase set up to use Firebase.

Authentication

The first thing we want to do when a user comes to our application is check if they are authenticated / logged in.

Normally we would need to set up an API backend to handle this, which can take a lot of time and effort. With Firebase, we have a few easy functions that take care of all of the hard work.

Firebase has a ton of different authentication methods we can use, but we first need to enable them on our project. We will be logging users in with email/password. On the Firebase console, click Authentication -> Sign-in methods -> and enable Email/Password.

Lets create an auth service which we will use to login, logout, signup a new user and check the auth state of our user.

Let’s use the Angular CLI again to generate service for us.

ng g service auth

Inside our service we’ll create a few functions using the Angular Fire Auth package.

import { Injectable } from "@angular/core";
import { AngularFireAuth } from "@angular/fire/auth";
import { from, Observable, of } from "rxjs";
 
@Injectable({
 providedIn: "root"
})
export class AuthService {
 constructor(private auth: AngularFireAuth) {}
 
 public checkLogin() {
   return from(this.auth.authState);
 }
 
 public login(email: string, password: string) {
   return from(this.auth.signInWithEmailAndPassword(email, password));
 }
 
 public logout() {
   return from(this.auth.signOut());
 }
 
 public signup(email: string, password: string) {
   return from(this.auth.createUserWithEmailAndPassword(email, password));
 }
}

Now let’s use the checkLogin function inside our app.component.ts to check if we have a user authenticated or not.

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './services/auth.service';
 
@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
 constructor(
   private authService: AuthService,
   private router: Router,
 ) {}
 
 public ngOnInit(): void {
   this.authService.checkLogin().subscribe((user) => {
     // check if we have a user logged in
     // if no user route to login route
     if (!user) {
       this.router.navigate(["login"]);
     }
   })
 }
}

If we do not have a user logged in, we will navigate them to the login route.

Inside our login component, let’s create two forms—one for logging the user in, and another for signing up a new user.

import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { AuthService } from 'src/app/services/auth.service';
 
@Component({
 selector: 'app-login',
 templateUrl: './login.component.html',
 styleUrls: ['./login.component.scss']
})
export class LoginComponent {
 public loginForm = new FormGroup({
   email: new FormControl("", [Validators.required, Validators.email]),
   password: new FormControl("", [Validators.required])
 });
 
 public signupForm = new FormGroup({
   email: new FormControl("", [Validators.required, Validators.email]),
   password: new FormControl("", [Validators.required])
 });
 
 constructor(private authService: AuthService) {}
 
 public login() {
   if (!this.loginForm.valid) {
     return;
   }
 
   this.authService.login(this.loginForm.value.email, this.loginForm.value.password)
     .subscribe((user) => {
       console.log(user);
     });
 }
 
 public signup() {
   if (!this.signupForm.valid) {
     return;
   }
 
   this.authService.signup(this.signupForm.value.email, this.signupForm.value.password)
     .subscribe((user) => {
       console.log(user);
     });
 }
 
}
 
<form [formGroup]="loginForm" (ngSubmit)="login()" class="ff-form">
 <h1>Login</h1>
 
 <mat-form-field appearance="outline">
   <mat-label>Email</mat-label>
   <input type="email" matInput formControlName="email" placeholder="Email">
   <mat-error *ngIf="loginForm.controls.email.hasError('required')">
     Email is <strong>required</strong>
   </mat-error>
   <mat-error *ngIf="loginForm.controls.email.hasError('email')">
     Email is <strong>invalid</strong>
   </mat-error>
 </mat-form-field>
 
 <mat-form-field appearance="outline">
   <mat-label>Password</mat-label>
   <input type="password" matInput formControlName="password" placeholder="Password">
   <mat-error *ngIf="loginForm.controls.password.hasError('required')">
     Password is <strong>required</strong>
   </mat-error>
 </mat-form-field>
 
 <button mat-raised-button color="primary" class="ff-form__submit">Login</button>
</form>
 
<form [formGroup]="signupForm" (ngSubmit)="signup()" class="ff-form">
 <h1>Signup</h1>
 
 <mat-form-field appearance="outline">
   <mat-label>Email</mat-label>
   <input type="email" matInput formControlName="email" placeholder="Email">
   <mat-error *ngIf="signupForm.controls.email.hasError('required')">
     Email is <strong>required</strong>
   </mat-error>
 </mat-form-field>
 
 <mat-form-field appearance="outline">
   <mat-label>Password</mat-label>
   <input type="password" matInput formControlName="password" placeholder="Password">
   <mat-error *ngIf="signupForm.controls.password.hasError('required')">
     Password is <strong>required</strong>
   </mat-error>
   <mat-error *ngIf="signupForm.controls.email.hasError('email')">
     Email is <strong>invalid</strong>
   </mat-error>
 </mat-form-field>
 
 <button mat-raised-button color="primary" class="ff-form__submit">Signup</button>
</form>

The above code is using Angular Material and Reactive Forms to create a form with email and password inputs.

When we submit either form we log or sign up a new user using the corresponding methods inside our auth.service.ts. Now within just a few simple methods, we have authentication set up in our app. 

Few things to note:

  • When a new user signs up, they are added to the users tab in authentication on the Firebase console.
  • We are not storing any other information about the user except for their email (and Firebase stores the password for authenticating). Once we set up a database we can store some user information needed for our app.
  • Check out the Firebase Auth docs for more info https://firebase.google.com/docs/auth 

 

Job Opportunities

Check current job openings

Find Us

  • 1595 Bedford Hwy, Suite 168
  • Bedford, NS B4A 3Y4
  • Canada

Located in Sunnyside Mall, near Pete's.

View on Google Maps

Business Inquiries

Media & Entertainment

Learning

Defence