Securing Angular 2 routes with Firebase authentication using AuthGuard

Attempting to create an AuthGuard for Angular 2 routes with Firebase Auth integration.

This is the implementation of the AuthGuard Service:

import { Injectable }             from '@angular/core';
import { CanActivate, Router,
         ActivatedRouteSnapshot,
         RouterStateSnapshot }    from '@angular/router';
import { AuthService }            from './auth.service';

@Injectable()
export class AuthGuard implements CanActivate {

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

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    if (this.AuthService.loggedIn) { return true; }

    this.router.navigate(['login']);
    return false;
  }
}

Here is the AuthService that verifies if a user is logged in and updates the 'loggedIn' property accordingly.

import { Injectable } from '@angular/core';
import { AngularFire } from 'angularfire2';
import { Router } from '@angular/router';

@Injectable()
export class AuthService {
loggedIn: boolean = false;

  constructor(
    public af: AngularFire,
    public router: Router) {
        af.auth.subscribe(user => {
            if(user){
                this.loggedIn = true;
            }
        });
    }
}

The main issue lies in the asynchrony problem. The canActivate() method in AuthGuard always returns false because the subscription does not update 'loggedIn' in time.

What is the recommended solution to address this?

UPDATE:

Modified the AuthGuard to return an observable.

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    return this.af.auth.map((auth) => {
        if (!auth) {
          this.router.navigateByUrl('login');
          return false;
        }
        return true;
    });
  }

Although it prevents redirection to the login page, the AuthGuarded component fails to render.

Uncertain whether the issue stems from my app.routes configuration. Here is the corresponding code snippet:

const routes: Routes = [
  { path: '', component: MainComponent, canActivate: [AuthGuard] },
  ...
];

export const routing = RouterModule.forRoot(routes);

Answer №1

To ensure the component renders properly, include .take(1) in the observable.

import {Observable} from "rxjs/Observable";
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    return this.af.auth.map((auth) => {
        if (!auth) {
          this.router.navigateByUrl('login');
          return false;
        }
        return true;
    }).take(1);
  }

Answer №2

If you are using newer versions of AngularFire, it is necessary to utilize authState instead:

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private afAuth: AngularFireAuth,
    private router: Router
  ) {}

  canActivate(): Observable<boolean> {
    return this.afAuth.authState
      .take(1)
      .map(authState => !!authState)
      .do(auth => !auth ? this.router.navigate(['/login']) : true);
  }
}

Remember to import take, map, and do from rxjs/add/operator.

Answer №3

After thorough testing, I have confirmed that this code is compatible with Angular 11 and Angular Fire version 6.

canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return this.authService.afAuth.authState.pipe(
  map(authState => !!authState),
  map(auth => {
    if (!auth) {
      this.router.navigate(['/sign-in']);
    }
    return auth;
  }),
 );
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue: Module "mongodb" could not be found when using webpack and typescript

I am encountering an issue while trying to use mongoose with webpack. Even though I have installed it as a dependency, when attempting to utilize the mongoose object and execute commands, it gives me an error stating that it cannot find the "." Module. Thi ...

How can you ensure an interface in typescript 3.0 "implements" all keys of an enum?

Imagine I have an enum called E { A = "a", B = "b"}. I want to enforce that certain interfaces or types (for clarity, let's focus on interfaces) include all the keys of E. However, I also need to specify a separate type for each field. Therefore, usi ...

Error message displayed indicating script not found after executing yarn tsc within a Docker container

Using docker, I successfully built my project by running yarn tsc. However, when I executed docker run -p88:5011 accounts2 I encountered the following error: PM2 error: Error: Script not found: /home/accounts/dist/server/index.js. This error occurs despit ...

What is the best approach for managing Create/Edit pages in Next.js - should I fetch the product data in ServerSideProps or directly in the component?

Currently, I am working on a form that allows users to create a product. This form is equipped with react-hook-form to efficiently manage all the inputs. I am considering reusing this form for the Edit page since it shares the same fields, but the data wil ...

Steps to obtain the download URL from AngularFireStorage after uploading the file using the getDownloadUrl() method

After successfully uploading images into my firebase storage, I want to retrieve the downloadURL and add it to my firestore database. When console logging "url", I am able to see the desired link. However, I am facing difficulties in using it. When attemp ...

Received corrupted file during blob download in Angular 7

When using Angular 7, I am making an API call by posting the URL file and attempting to download it using the 'saveAs' function from the fileSaver library. The file is successfully downloading, but it appears to be corrupted and cannot be opened. ...

Discovering the functionality of mock objects in unit testing with Angular and Jasmine

Currently, I am delving into the world of unit testing and Angular as a newbie. I have been exploring different tutorials and articles that focus on unit testing for HTTP in Angular. I find myself struggling to comprehend the purpose of httpMock when usin ...

Unable to integrate BokehJS with Angular8

Here is the error log that appeared in the browser: AppComponent.html:1 ERROR TypeError: FlatBush is not a constructor at new SpatialIndex (vendor.js:90501) at AnnularWedgeView.push../node_modules/bokehjs/build/js/lib/models/glyphs/xy_glyph.js.XYG ...

Tips for creating an HTTP only cookie in NestJS

Currently, I am in the process of incorporating JWT authorization with both an accessToken and refreshToken. The requirement is to store these tokens in HTTP-only cookies. Despite attempting this code snippet, I have encountered an issue where the cookies ...

What is the best way to retrieve Firebase data and assign it to a variable in React after using setState

Working with react and firebase real-time database for the first time has been quite challenging. I'm struggling to extract the data and insert it into a constant called items. It seems like the firebase code is asynchronous, which means it executes a ...

Angular 2 Release Candidate 5 has encountered an issue in platform-browser.umd.js. The error message states: "An error has occurred that was

I am currently utilizing a service to send a request. homepage.service.ts import { Injectable } from "@angular/core"; import { Http, Response } from "@angular/http"; import { Observable } from "rxjs/Observable"; import { PATH } from "../const/config"; ...

Utilizing the expression in *ngIf directive in Angular 2 allows for

Currently, I am exploring the possibility of utilizing a function's return value in *ngIf within Angular 2. I conducted an experiment <ion-fab right bottom *ngIf="shouldDisplayFlag()"> Unfortunately, an error is being encountered during this ...

Unable to resolve all dependencies for UserService: (Http, ?)

After transitioning to the latest Angular2 version 2.0.0-beta.17, my project started experiencing issues. The structure of my UserService is as follows: import { Injectable} from '@angular/core'; import { Http } from '@angular/http'; ...

Ways to merge values across multiple arrays

There is a method to retrieve all unique properties from an array, demonstrated by the following code: var people = [{ "name": "John", "age": 30 }, { "name": "Anna", "job": true }, { "name": "Peter", "age": 35 }]; var result = []; people. ...

Utilizing MongoDB to create time-based event triggers

I am working on a front-end application using Angular and a back-end system powered by Express.js. My goal is to have notifications displayed on the front end based on meetings scheduled at specific times. For example: If there is a meeting scheduled f ...

Exploring the contrast of utilizing the `new Date()` function compared to Firestore's `new

I am developing a new app and need to calculate the time elapsed between the start and end of a run. When the run starts, I record a timestamp using the new Date() function in Firebase. (I opted for this over firestore fieldValue to avoid conflicts with o ...

Creating various import patterns and enhancing Intellisense with Typescript coding

I've been facing challenges while updating some JavaScript modules to TypeScript while maintaining compatibility with older projects. These older projects utilize the commonjs pattern const fn = require('mod');, which I still need to accommo ...

Script execution in '<URL>' has been prevented due to sandboxing of the document's frame and the absence of the 'allow-scripts' permission setting

When I deploy my pure Angular application with a REST API to a production server and try to access its URL from another site (such as a link in an email), I encounter a strange problem. Firefox doesn't provide any error message, but Chrome says: Blo ...

Having trouble getting dynamic values to render properly in Ionic select? Find a solution in Ionic 4

Encountering an issue with Ionic 4 and ion-select. The problem arises when attempting to bind data, specifically when preselecting data. In this scenario, the ion-select element fails to render properly. <ion-item class="transparent"> ...

What is the process for specifying a method on a third-party class in TypeScript?

I'm facing a challenge while trying to extend a third-party class in TypeScript. The issue is that I am unable to access any existing methods of the class within my new method. One possible solution could be to redeclare the existing methods in a sep ...