Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular router won't navigate in http interceptor

I'm trying to redirect users to a login page if they are unauthenticated or their token has expired. My interceptor works properly, but the angular router isn't redirecting them. If I use window.location.href = "/login" then it works fine, but obviously this isn't the angular way and also causes my app to reload. Here is my current http interceptor:

import { Injectable } from '@angular/core';
import {
    HttpRequest,
    HttpHandler,
    HttpEvent,
    HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { AuthService } from '../services/auth.service';
import { Router } from '@angular/router';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {

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

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return this.authService.getSession().mergeMap(session => {
            if (session) {
                if (session.getIdToken().decodePayload().passwordExpired == 'true' && !this.router.url.includes('change-password')) {
                    // this navigation does not work
                    this.router.navigate(['/login/change-password'])
                } else if (request.url.includes(this.authService.awsUrl) || request.url.includes(this.authService.userUrl)) {
                    request = request.clone({
                        setHeaders: {
                            Authorization: `Bearer ${session.getIdToken().getJwtToken()}`
                        }
                    });
                }
                return next.handle(request);
            } else if (this.router.url.includes('login') || this.router.url.includes('provision')) {
                return next.handle(request);
            } else {
                //this navigation also does not work
                this.router.navigate(['/login']);
                return Observable.throw('token is not valid');
            }
        });
    }
}

I've also tried putting the navigation inside a method in my auth service, but that also does not work. Am I doing something wrong here? or am I just missing something small that is causing the router to hang? I'm on angular v6 if that makes any difference.

like image 468
Lance Martin Avatar asked Sep 20 '25 15:09

Lance Martin


1 Answers

In my opinion, this logic should be removed from the interceptor entirely.

Angular Router has build in Guard options protecting routes. See https://angular.io/guide/router#the-sample-application to view the different guard types.

With this, you can check for user authentication before a user is permitted to view a route, this is where the logic would go for your reroutes you are attempting based on your scenarios.

Once the user is authorized, they pass through to the desired route where the API calls will take place, which then pass through the interceptor and back to the component making the calls.

In short,

  • Auth Guards should be used to validate and authorize users before they are permitted to view a route. If a user is unauthorized for any reason, reroute to the appropriate route.
  • Interceptors should be used to modify HTTP calls before they leave the app and when they are first returned to the app. Here you would set your headers, modify endpoints through env variables, etc.
like image 85
mrtpain Avatar answered Sep 22 '25 08:09

mrtpain