I'm attempting to add a Route Guard that will send a JWT to a PHP API that will return true or false depending on if the user is authenticated. Through my testing, the Route Guard works until it actually calls the API. If the API returns false, the guard works as expected. However, if the API returns true, then the guard seems to want to redirect the user as if it had returned false, but instead of displaying the home screen, it just displays a nothing.
auth.guard.ts
canActivate(): boolean {
if (localStorage.getItem('portfolioJWT') === null) {
this.router.navigate(['/']);
return false;
} else {
const token = JSON.parse(localStorage.getItem('portfolioJWT'));
this.authService.isAuth(token).subscribe(res => {
console.log(res);
if(!res) {
this.router.navigate(['/']);
console.log("NOT Authorized");
return false;
} else {
console.log("Authorized");
return true;
}
});
}
}
auth.service.ts
isAuth(token: string): Observable<Boolean> {
const authHttpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + token
})
};
return this.http.post<Boolean>('http://portfolioapi/api/checkAuth', {}, authHttpOptions);
}
I have the guard console logging the returned value, and whether or not the user is authorized, which it does and it shows the correct data.
The problem may be that you are not using a Promise<boolean>
for the canActivate, so while canActivate is still executing in the background,
the router already moved on, thus triggering unexpected behaviour.
An example may be that the API returns false
and initializes a navigate
, but only after the router already navigated you somewhere (that may trigger the blank page). Same goes for the console.log(res)
. It may work, but it's already too late, the router has moved on.
What you want to achieve is that the routing should pause until is has received either true of false. Checking for a local variable's value may work fine without a Promise, but it does matter when performing an API call, because it is asynchronous, so you explicitly need the tell the router to wait for the call to finish.
canActivate(): Promise<boolean> {
return new Promise((resolve) => {
if (localStorage.getItem('portfolioJWT') === null) {
this.router.navigate(['/']);
resolve(false);
} else {
const token = JSON.parse(localStorage.getItem('portfolioJWT'));
this.authService.isAuth(token).subscribe(res => {
console.log(res);
if(!res) {
this.router.navigate(['/']);
console.log("NOT Authorized");
resolve(false)
} else {
console.log("Authorized");
resolve(true)
}
});
}
})
}