Reputation: 103
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.
Upvotes: 4
Views: 8140
Reputation: 911
If you want to place router navigation, then you must place this code in tap function, for example:
return next.handle(tokenizedReq).pipe(
tap({
error: (res) => {
this.route.navigate(['/error'])
console.log("tap, error", res);
}
}),
catchError(this.errorHandler) // this.errorHandler is a function
);
Upvotes: 2
Reputation: 103
Some further information incase it helps someone that stumbles upon this problem in the future. I took the advice from the accepted answer and moved my redirect logic into an auth guard and an error interceptor, but even after the refactoring, router.navigate(['/login'])
still wasn't working. I ended up realizing that the router was hanging due to my auth guard never resolving in the case of a user not being authenticated. After making the guard resolve the redirects worked perfectly.
Upvotes: 1
Reputation: 305
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,
Upvotes: 9