Angular 14 Firebase Authentication Example; In this tutorial, we will learn how to build the Angular 14 Firebase Authentication System from scratch using the Firebase Real-time NoSQL cloud database.
We will be covering the following topics in this Angular guide:
- Sign In with google
- Sign In with a Username/password
- Sign Up with an Email/password
- Recover forget password
- Send Email Verification to a newly created user
- Protect or secure inner pages routes using CanActivate Guard
- Restrict Access of non-authentication users
- Manage the logged-in state of Firebase user with LocalStorage
Now, we will learn all the above-mentioned topics step by step:
Step 1- Getting Started
First of all, we have to make sure that we already have Node Js set up on our local development system.
So, now, we have to install the Angular CLI:
npm install -g @angular/cli
Then, we will create an Angular app using the below command to set up the Angular project:
ng new angularfiebase-authentication
After downloading the project, we will get into the project directory:
cd angularfirebase-authentication
Further, we need to install the Bootstrap CSS framework in the Angular app:
npm install bootstrap
Then, we go to the angular.json file and replace the given code with “styles”: [] array:
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.scss"
]
Step 2- SetUp firebase Packages
After setting up the Firebase project, we will install the Firebase packages:
npm install firebase @angular/fire
Now, we have to add our Firebase configuration in the environment.ts file:
export const environment = {
production: false,
firebase: {
apiKey: "xxxxxxxx-xxxxxxxx",
authDomain: "xxxxxxxxxxxxxxxxxxxxxxxx",
databaseURL: "xxxxxxxxxxxxxxxxxxxxxxxx",
projectId: "xxxxxxxx",
storageBucket: "xxxxxxxx",
messagingSenderId: "xxxxxx",
appId: "xxxxx",
measurementId: "xxxxxxxxxxxxxxxx"
}
};
Here, we will import and register the Firebase modules in the app.module.ts:
// Firebase services + environment module
import { AngularFireModule } from '@angular/fire/compat';
import { AngularFireAuthModule } from '@angular/fire/compat/auth';
import { AngularFireStorageModule } from '@angular/fire/compat/storage';
import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
import { AngularFireDatabaseModule } from '@angular/fire/compat/database';
import { environment } from '../environments/environment';
@NgModule({
imports: [
AngularFireModule.initializeApp(environment.firebase),
AngularFireAuthModule,
AngularFirestoreModule,
AngularFireStorageModule,
AngularFireDatabaseModule,
]
})
Step 3- Generate Angular Components
In order to create a complete Angular Firebase Authentication System, we have to generate the Angular components:
ng g c components/dashboard
ng g c components/sign-in
ng g c components/sign-up
ng g c components/forgot-password
ng g c components/verify-email
Step 4- Create The Angular Routes
Here, we will create the app-routing.module.ts file inside the src/app/ directory and then add the below code to it:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SignInComponent } from './components/sign-in/sign-in.component';
import { SignUpComponent } from './components/sign-up/sign-up.component';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { ForgotPasswordComponent } from './components/forgot-password/forgot-password.component';
import { VerifyEmailComponent } from './components/verify-email/verify-email.component';
const routes: Routes = [
{ path: '', redirectTo: '/sign-in', pathMatch: 'full' },
{ path: 'sign-in', component: SignInComponent },
{ path: 'register-user', component: SignUpComponent },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'forgot-password', component: ForgotPasswordComponent },
{ path: 'verify-email-address', component: VerifyEmailComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
Enable the route within the view, and add the below code in the app.component.html file:
<router-outlet></router-outlet>
Step 5- Create Firebase Authentication Service
Afterward, we will generate the auth service and user interface files to create a Firebase Authentication System with Angular:
ng g i shared/services/user
ng g s shared/services/auth
Now, we go to the shared/services/user.ts
This user interface class is a schema for User object:
export interface User {
uid: string;
email: string;
displayName: string;
photoURL: string;
emailVerified: boolean;
}
Step 6- Create Auth Service
This file holds the core logic of our authentication system. In this will be covered the social login using Firebase’s Google Auth provider. We can also create the login with Facebook, Twitter and GitHub later on.
The auth service will cover the sign-in with username/password, sign-up with sign-in with email/password, password reset, email verification and route protection using the canActivate auth guard method.
Now, we need to update the code in the app shared/services/auth.service.ts file:
import { Injectable, NgZone } from '@angular/core';
import { User } from '../services/user';
import * as auth from 'firebase/auth';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import {
AngularFirestore,
AngularFirestoreDocument,
} from '@angular/fire/compat/firestore';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root',
})
export class AuthService {
userData: any; // Save logged in user data
constructor(
public afs: AngularFirestore, // Inject Firestore service
public afAuth: AngularFireAuth, // Inject Firebase auth service
public router: Router,
public ngZone: NgZone // NgZone service to remove outside scope warning
) {
/* Saving user data in localstorage when
logged in and setting up null when logged out */
this.afAuth.authState.subscribe((user) => {
if (user) {
this.userData = user;
localStorage.setItem('user', JSON.stringify(this.userData));
JSON.parse(localStorage.getItem('user')!);
} else {
localStorage.setItem('user', 'null');
JSON.parse(localStorage.getItem('user')!);
}
});
}
// Sign in with email/password
SignIn(email: string, password: string) {
return this.afAuth
.signInWithEmailAndPassword(email, password)
.then((result) => {
this.SetUserData(result.user);
this.afAuth.authState.subscribe((user) => {
if (user) {
this.router.navigate(['dashboard']);
}
});
})
.catch((error) => {
window.alert(error.message);
});
}
// Sign up with email/password
SignUp(email: string, password: string) {
return this.afAuth
.createUserWithEmailAndPassword(email, password)
.then((result) => {
/* Call the SendVerificaitonMail() function when new user sign
up and returns promise */
this.SendVerificationMail();
this.SetUserData(result.user);
})
.catch((error) => {
window.alert(error.message);
});
}
// Send email verfificaiton when new user sign up
SendVerificationMail() {
return this.afAuth.currentUser
.then((u: any) => u.sendEmailVerification())
.then(() => {
this.router.navigate(['verify-email-address']);
});
}
// Reset Forggot password
ForgotPassword(passwordResetEmail: string) {
return this.afAuth
.sendPasswordResetEmail(passwordResetEmail)
.then(() => {
window.alert('Password reset email sent, check your inbox.');
})
.catch((error) => {
window.alert(error);
});
}
// Returns true when user is looged in and email is verified
get isLoggedIn(): boolean {
const user = JSON.parse(localStorage.getItem('user')!);
return user !== null && user.emailVerified !== false ? true : false;
}
// Sign in with Google
GoogleAuth() {
return this.AuthLogin(new auth.GoogleAuthProvider()).then((res: any) => {
this.router.navigate(['dashboard']);
});
}
// Auth logic to run auth providers
AuthLogin(provider: any) {
return this.afAuth
.signInWithPopup(provider)
.then((result) => {
this.router.navigate(['dashboard']);
this.SetUserData(result.user);
})
.catch((error) => {
window.alert(error);
});
}
/* Setting up user data when sign in with username/password,
sign up with username/password and sign in with social auth
provider in Firestore database using AngularFirestore + AngularFirestoreDocument service */
SetUserData(user: any) {
const userRef: AngularFirestoreDocument<any> = this.afs.doc(
`users/${user.uid}`
);
const userData: User = {
uid: user.uid,
email: user.email,
displayName: user.displayName,
photoURL: user.photoURL,
emailVerified: user.emailVerified,
};
return userRef.set(userData, {
merge: true,
});
}
// Sign out
SignOut() {
return this.afAuth.signOut().then(() => {
localStorage.removeItem('user');
this.router.navigate(['sign-in']);
});
}
}
After that, we go to the app.module.ts file and import the authentication service and pass the AuthService class into the providers: [AuthService] array. By doing this, our authentication service will be available throughout the application:
// Auth service
import { AuthService } from "./shared/services/auth.service";
@NgModule({
declarations: [...],
imports: [...],
providers: [AuthService],
bootstrap: [...]
})
Step 7- Create Angular Login With Firebase API
Now, we will be using the AuthService class. It will help us create Login authentication in Angular with Firebase.
We will focus on:
- Sign-in with Username and Password
- Sign-in with Gmail or Google auth
We need to import AuthService onto sign-in/sign-in.components.ts. Then, inject AuthService into the constructor:
import { Component, OnInit } from '@angular/core';
import { AuthService } from "../../shared/services/auth.service";
@Component({
selector: 'app-sign-in',
templateUrl: './sign-in.component.html',
styleUrls: ['./sign-in.component.scss']
})
export class SignInComponent implements OnInit {
constructor(
public authService: AuthService
) { }
ngOnInit() { }
}
Here, we have to place the below code inside the sign-in/sign-in.component.html file:
<div class="displayTable">
<div class="displayTableCell">
<div class="authBlock">
<h3>Sign In</h3>
<div class="formGroup">
<input type="text" class="formControl" placeholder="Username" #userName required>
</div>
<div class="formGroup">
<input type="password" class="formControl" placeholder="Password" #userPassword required>
</div>
<!-- Calling SignIn Api from AuthService -->
<div class="formGroup">
<input type="button" class="btn btnPrimary" value="Log in" (click)="authService.SignIn(userName.value, userPassword.value)">
</div>
<div class="formGroup">
<span class="or"><span class="orInner">Or</span></span>
</div>
<!-- Calling GoogleAuth Api from AuthService -->
<div class="formGroup">
<button type="button" class="btn googleBtn" (click)="authService.GoogleAuth()">
<i class="fab fa-google-plus-g"></i>
Log in with Google
</button>
</div>
<div class="forgotPassword">
<span routerLink="/forgot-password">Forgot Password?</span>
</div>
</div>
<div class="redirectToLogin">
<span>Don't have an account?<span class="redirect" routerLink="/register-user"> Sign Up</span></span>
</div>
</div>
</div>
Step 8- User Registration With Angular Firebase
In this step, we will register the user with Angular and Firebase.
We go to sign-up/sign-up.component.ts and add the below code:
import { Component, OnInit } from '@angular/core';
import { AuthService } from "../../shared/services/auth.service";
@Component({
selector: 'app-sign-up',
templateUrl: './sign-up.component.html',
styleUrls: ['./sign-up.component.scss']
})
export class SignUpComponent implements OnInit {
constructor(
public authService: AuthService
) { }
ngOnInit() { }
}
Then, we will go to sign-up/sign-up.component.html and add the below code in it:
<div class="displayTable">
<div class="displayTableCell">
<div class="authBlock">
<h3>Sign Up</h3>
<div class="formGroup">
<input
type="email"
class="formControl"
placeholder="Email Address"
#userEmail
required
/>
</div>
<div class="formGroup">
<input
type="password"
class="formControl"
placeholder="Password"
#userPwd
required
/>
</div>
<div class="formGroup">
<input
type="button"
class="btn btnPrimary"
value="Sign Up"
(click)="authService.SignUp(userEmail.value, userPwd.value)"
/>
</div>
<div class="formGroup">
<span class="or"><span class="orInner">Or</span></span>
</div>
<!-- Continue with Google -->
<div class="formGroup">
<button
type="button"
class="btn googleBtn"
(click)="authService.GoogleAuth()"
>
<i class="fab fa-google-plus-g"></i>
Continue with Google
</button>
</div>
</div>
<div class="redirectToLogin">
<span
>Already have an account?
<span class="redirect" routerLink="/sign-in">Log In</span></span
>
</div>
</div>
</div>
Step 9- Angular Forgot Password With Firebase
We are going to create the forgot password feature using Firebase in Angular.
Now, we need to go to the forgot-password.component.ts to add the given code:
import { Component, OnInit } from '@angular/core';
import { AuthService } from "../../shared/services/auth.service";
@Component({
selector: 'app-forgot-password',
templateUrl: './forgot-password.component.html',
styleUrls: ['./forgot-password.component.scss']
})
export class ForgotPasswordComponent implements OnInit {
constructor(
public authService: AuthService
) { }
ngOnInit() {
}
}
Here, we will go to the forgot-password.component.html to add the below code:
<div class="displayTable">
<div class="displayTableCell">
<div class="authBlock">
<h3>Reset Password</h3>
<p class="text-center">Please enter your email address to request a password reset.</p>
<div class="formGroup">
<input type="email" class="formControl" placeholder="Email Address" #passwordResetEmail required>
</div>
<!-- Calling ForgotPassword from AuthService Api -->
<div class="formGroup">
<input type="submit" class="btn btnPrimary" value="Reset Password" (click)="authService.ForgotPassword(passwordResetEmail.value)">
</div>
</div>
<div class="redirectToLogin">
<span>Go back to ? <span class="redirect" routerLink="/sign-in">Log In</span></span>
</div>
</div>
</div>
Step 10- Send Verification Email
Firebase allows us to send verification emails easily. We simple have to add the code in verify-email/verify-email.components:
import { Component, OnInit } from '@angular/core';
import { AuthService } from "../../shared/services/auth.service";
@Component({
selector: 'app-verify-email',
templateUrl: './verify-email.component.html',
styleUrls: ['./verify-email.component.scss']
})
export class VerifyEmailComponent implements OnInit {
constructor(
public authService: AuthService
) { }
ngOnInit() {
}
}
further, we go to src/app/components/verify-email/verify-email.component.html and include the code:
<div class="displayTable">
<div class="displayTableCell">
<div class="authBlock">
<h3>Thank You for Registering</h3>
<div class="formGroup" *ngIf="authService.userData as user">
<p class="text-center">We have sent a confirmation email to <strong>{{user.email}}</strong>.</p>
<p class="text-center">Please check your email and click on the link to verfiy your email address.</p>
</div>
<!-- Calling SendVerificationMail() method using authService Api -->
<div class="formGroup">
<button type="button" class="btn btnPrimary" (click)="authService.SendVerificationMail()">
<i class="fas fa-redo-alt"></i>
Resend Verification Email
</button>
</div>
</div>
<div class="redirectToLogin">
<span>Go back to?<span class="redirect" routerLink="/sign-in"> Sign in</span></span>
</div>
</div>
</div>
Step 11- Use Route Guard To Protect Angular Routes
Now, we will see how to protect routes from unauthorized access. For that, we will head over to auth.service.ts and look for the isLoggedIn() method. This function returns the boolean result to true when the user is logged in. If the user is not found, then it will return false and doesn’t allow users to access the desired pages:
// Returns true when user is looged in and email is verified
get isLoggedIn(): boolean {
const user = JSON.parse(localStorage.getItem('user'));
return (user !== null && user.emailVerified !== false) ? true : false;
}
We have to secure the inner pages. to get this functionality, we have to generate route guard files.
We will execute the command to create the route guards:
ng generate guard shared/guard/auth
Here, we have to go to auth.guards.ts and place the code in it:
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from "../../shared/services/auth.service";
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
public authService: AuthService,
public router: Router
){ }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if(this.authService.isLoggedIn !== true) {
this.router.navigate(['sign-in'])
}
return true;
}
}
We have successfully secured the application routes. now, the user needs to be authenticated before accessing the app’s inner pages.
Then, we will open the app-route.module.ts file and import the route guard in the Angular routing file:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SignInComponent } from './components/sign-in/sign-in.component';
import { SignUpComponent } from './components/sign-up/sign-up.component';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { ForgotPasswordComponent } from './components/forgot-password/forgot-password.component';
import { VerifyEmailComponent } from './components/verify-email/verify-email.component';
// route guard
import { AuthGuard } from './shared/guard/auth.guard';
const routes: Routes = [
{ path: '', redirectTo: '/sign-in', pathMatch: 'full' },
{ path: 'sign-in', component: SignInComponent },
{ path: 'register-user', component: SignUpComponent },
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
{ path: 'forgot-password', component: ForgotPasswordComponent },
{ path: 'verify-email-address', component: VerifyEmailComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
Step 12- Manage firebase User Authentication State With LocalStorage
We have already set up the code for managing the user authentication state with the localStorage API in the auth service class.
Now, we have to save the user state in Local Storage when the user is logged in. User details will be available even if we refresh the page. Also, we have to remove the user data from the local storage if we log out from the app.
Therefore, we head over to the dashboard.component.html file and add the given code to it:
<!-- Top navigation -->
<nav class="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow">
<a class="navbar-brand col-sm-3 col-md-2 mr-0">
<img class="brand-logo" src="assets/logo-positronx-white.svg" alt="positronX.io Logo">
</a>
</nav>
<!-- Sidebar navigation -->
<div class="container-fluid">
<div class="row">
<nav class="col-md-2 d-md-block bg-light sidebar">
<div class="sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active">
<i class="fas fa-user"></i>User Profile
</a>
</li>
<!-- Calling SignOut() Api from AuthService -->
<li class="nav-item">
<a class="nav-link" (click)="authService.SignOut()">
<i class="fas fa-sign-out-alt"></i>Log out
</a>
</li>
</ul>
</div>
</nav>
<!-- Main content -->
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4">
<div class="inner-adjust">
<div class="pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">User Profile</h1>
</div>
<!-- Show user data when logged in -->
<div class="row" *ngIf="authService.userData as user">
<div class="col-md-12">
<div class="media">
<img class="align-self-start mr-5 img-thumbnail rounded-circle" src="{{(user.photoURL) ? user.photoURL : '/assets/dummy-user.png'}}"
alt="{{user.displayName}}">
<div class="media-body">
<h1>Hello: <strong>{{(user.displayName) ? user.displayName : 'User'}}</strong></h1>
<p>User ID: <strong>{{user.uid}}</strong></p>
<p>Email: <strong>{{user.email}}</strong></p>
<p>Email Verified: <strong>{{user.emailVerified}}</strong></p>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
Next, we add the auth service class in the dashboard.component.ts file:
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../shared/services/auth.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss'],
})
export class DashboardComponent implements OnInit {
constructor(public authService: AuthService) {}
ngOnInit(): void {}
}
Start the Angular authentication project in the browser:
ng serve --open
Conclusion
Hope that this Angular tutorial about Angular 14 firebase Authentication was a smooth and easy one for you to follow.
Thanks