Handling Token Expiry Using Angular Interceptors

Overview

In most Angular apps, HTTP Interceptors are used to append tokens (like JWT) to every API call for authentication. This works fine until the token expires, and things can break silently.

Real Issue Faced

In one of our projects, once the user's token expired, the API started returning 401 (Unauthorized) responses. But the app was not showing any error to the user. So, the users kept clicking around, thinking everything was working when in fact, nothing was really saving.

Why the Problem Happened?

The interceptor for adding tokens to headers was there, but error responses were not handled. So, when the token expired, the API rejected the request, and the user wasn't redirected to the login page or shown a message.

Solution

We updated the interceptor to handle 401 errors globally. If a 401 response is detected, we automatically log the user out and redirect them to the login page.

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  const token = this.authService.getToken();

  const cloned = req.clone({
    setHeaders: {
      Authorization: `Bearer ${token}`
    }
  });

  return next.handle(cloned).pipe(
    catchError(err => {
      if (err.status === 401) {
        this.authService.logout();              // Clear token
        this.router.navigate(['/login']);       // Redirect to login
      }
      return throwError(() => err);
    })
  );
}

To avoid redirecting multiple times when several 401s occur at once, we added a flag to ensure that the logout happens only once.

if (!this.authService.logoutInProgress) {
  this.authService.logoutInProgress = true;
  this.authService.logout();
  this.router.navigate(['/login']);
}

Conclusion

HTTP Interceptors in Angular are powerful, not just for attaching tokens but also for handling common error cases. Handling 401 errors in one place saves a lot of repetitive code and gives users a clear experience when their session expires.