We often need to restrict access to specific routes in Angular apps based on whether a user is logged in or has specific permissions. To safeguard these routes, Angular provides Route Guards, such as CanActivate.
We had to restrict user access to the dashboard in one of our projects unless they were authenticated. Using CanActivate, we developed an AuthGuard and included logic to determine whether the user token was stored locally. Up until we released the app, everything was operating smoothly.
Even though they were already logged in, some users complained that they kept getting redirected to the login page.
Reasons for the Problem
We found that timing was the cause of the problem. The guard attempted to verify the token before the validation was finished, even though the app had already called the API to validate the token at startup. It is therefore believed that the user was not authenticated.
How did we fix it?
Our AuthGuard logic has been modified to wait for validation to complete before granting or denying access. We used a shared AuthService with an isAuthenticated$ observable rather than just checking local storage.
Here’s how we adjusted the AuthGuard.
canActivate(): Observable<boolean> {
return this.authService.isAuthenticated$.pipe(
take(1),
map(isAuth => {
if (!isAuth) {
this.router.navigate(['/login']);
return false;
}
return true;
})
);
}
And in the AuthService, we updated the token status using a BehaviorSubject once the API response came back.
private authStatus = new BehaviorSubject<boolean>(false);
isAuthenticated$ = this.authStatus.asObservable();
validateToken() {
// Call backend to validate token
this.http.get('/api/validate-token').subscribe(
() => this.authStatus.next(true),
() => this.authStatus.next(false)
);
}
We called validateToken() once in AppComponent during app initialization.
Conclusion
Route guards are essential for secure routing in Angular apps. But they must be carefully integrated with authentication logic, especially when token validation involves an async call. Using an observable approach helps in handling real-time state and avoiding premature navigation decisions.