Piyush Kumar
Piyush Kumar

Reputation: 551

Angular Authgaurd making requests in infinite loop when error

I am trying to protect my routes using authGaurd.

auth.service.ts

import { Injectable } from '@angular/core';
import { environment } from '../../../environments/environment';
import { Router, CanActivate } from '@angular/router';
import { HttpClient, HttpHeaders } from '@angular/common/http';

import { Observable } from 'rxjs/Observable';

import { Response } from '../response.model';

const httpOptionsSecure = {
    headers: new HttpHeaders({'Content-Type': 'application/json', 'Authorization': 'Bearer ' + localStorage.getItem("authToken")})
}

@Injectable()
export class AuthService implements CanActivate {

    private baseUrl: string = environment.baseUrl + "auth/";
    private signInUrl: string = this.baseUrl + "signIn";
    private verifyUserUrl: string = this.baseUrl + "verify";

    constructor(private http: HttpClient, public router: Router) {

    }


    canActivate(): Observable<boolean> {
        return new Observable((observer) => {
            this.verifyUser().subscribe((res) => {
                if (res.code === 200 && res.isSuccess === true) observer.next(true);
                else observer.next(false);
            }, (err) => {
                console.log("Err: ", err);
                this.router.navigate(['/','login']);
                observer.next(false);
            });
        });
    }

    // Verify loggedIn User
    verifyUser(): Observable<Response> {
        return this.http.post<Response>(this.verifyUserUrl, {}, httpOptionsSecure);
    }

So whenever I am trying to go to the protected page and whenever the response from server is 400 code then the request is made again in infinte loop.

I am kind of new to angular, I don't know what am I doing wrong.

Thanks in advance.

Upvotes: 3

Views: 5450

Answers (1)

JeanPaul A.
JeanPaul A.

Reputation: 3724

Most probably you are entering an infinite loop because the / path is being redirected to a path which is protected by the AuthGuard itself.

So for example. You try to access Route A, which is protected by the guard, which redirects to route B (the base route / ), and route B could be redirecting (view redirectTo attributes in the route) to route C which is also protected by the AuthGuard, resulting in the following routes.

A -> B -> C -> B -> C...

Make sure that the routing definition is correct.

Note that a route guard is activated for each Route that it is associated with

So for example if you have

/            <- Associated with an Auth Guard
/route1      <- Child of /
/route2      <- Child of /

with the following route definition

let routes:Routes = [
    { 
       path: '',
       canActivate: [ AuthGuard ]
       children: [
         { path: '', redirectTo: 'route1', pathMatch:'full' },
         { path: 'route1' },
         { path: 'route2' }
       ]
    }
];

Trying to access either of the routes, will trigger the AuthGuard associated with route /. If you go for example, to route1, the auth Guard will trigger, which will redirect to / which will redirect again to route1 and the cycle begins again.

I suggest to read this documentation guide for further information how routing works in angular.

Furthermore, the use of Observables does not have to do with Angular, but is RxJS.

Your code can be simplified as below

For RxJS 5.5.x +

import { Observable } from 'rxjs/Observable';
import { catchError, map, of } from 'rxjs/operators';

canActivate(): Observable<boolean> {
    return this.verifyUser().pipe(map((res) => {
        if (res.code === 200 && res.isSuccess === true) {
            return true;
        } 

        this.router.navigate(['/','login']);
        return false;
    }, catchError((err) => {
        console.log("Err: ", err);
        this.router.navigate(['/','login']);
        return of(false);
    }));
}

// Verify loggedIn User
verifyUser(): Observable<Response> {
    return this.http.post<Response>(this.verifyUserUrl, {}, httpOptionsSecure);
}

For RxJS 5.4.x and below

canActivate(): Observable<boolean> {
    return this.verifyUser().map((res) => {
        if (res.code === 200 && res.isSuccess === true) {
            return true;
        } 

        this.router.navigate(['/','login']);
        return false;
    }).catch((err) => {
        console.log("Err: ", err);
        this.router.navigate(['/','login']);
        return Observable.of(false);
    });
}

// Verify loggedIn User
verifyUser(): Observable<Response> {
    return this.http.post<Response>(this.verifyUserUrl, {}, httpOptionsSecure);
}

Upvotes: 6

Related Questions