Angular 4.3 - HTTP Interceptor - refresh JWT token

Viewed 8335

I need to react (in interceptor class) on 403 Forbidden HTTP status (to obtain/refresh) JWT token and retry the request with fresh token.

In the code below, when server return error response it goes to success callback (not into the error callback as I expect) and the event is typeof object (which is useless in reaction on error response). The event object looks like this: {type:0}.

Question:

-How to properly handle httpErrorResponse (403 Forbidden) in HttpInterceptor when I need refresh accessToken and retry the http request?

 import {
  HttpInterceptor,
  HttpRequest,
  HttpResponse,
  HttpHandler,
  HttpEvent
} from '@angular/common/http';
import 'rxjs/add/operator/map';

@Injectable()
class JWTInterceptor implements HttpInterceptor {

  constructor(private tokenService: TokenService) {}
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  let myHeaders = req.headers;
  if (this.tokenService.accessToken) {
        myHeaders = myHeaders.append('Authorization',`${this.tokenService.accessToken.token_type} ${this.tokenService.accessToken.access_token}`)
   }

  const authReq = req.clone({headers: myHeaders});

    return next.handle(authReq).map((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse) {
        // success callback
      }
    }, (err: any) => {
      if (err instanceof HttpErrorResponse {
        if (err.status === 403) {
          // error callback
          this.tokenService.obtainAccessToken()
        }
      }
    })
      .retry(1);
  }
}
4 Answers

Just wanted to share what worked for me:

@Injectable()
export class AutoReLoginInterceptor implements HttpInterceptor {

    constructor() {
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // as we want to intercept the possible errors, instead of directly returning the request execution, we return an Observable to control EVERYTHING
        return new Observable<HttpEvent<any>>(subscriber => {

            // first try for the request
            next.handle(req)
                .subscribe((event: HttpEvent<any>) => {
                        if (event instanceof HttpResponse) {
                            // the request went well and we have valid response
                            // give response to user and complete the subscription
                            subscriber.next(event);
                            subscriber.complete();
                        }
                    },
                    error => {
                        if (error instanceof HttpErrorResponse && error.status === 401) {
                            console.log('401 error, trying to re-login');

                            // try to re-log the user
                            this.reLogin().subscribe(authToken => {
                                // re-login successful -> create new headers with the new auth token
                                let newRequest = req.clone({
                                    headers: req.headers.set('Authorization', authToken)
                                });

                                // retry the request with the new token
                                next.handle(newRequest)
                                    .subscribe(newEvent => {
                                        if (newEvent instanceof HttpResponse) {
                                            // the second try went well and we have valid response
                                            // give response to user and complete the subscription
                                            subscriber.next(newEvent);
                                            subscriber.complete();
                                        }
                                    }, error => {
                                        // second try went wrong -> throw error to subscriber
                                        subscriber.error(error);
                                    });
                            });
                        } else {
                            // the error was not related to auth token -> throw error to subscriber
                            subscriber.error(error);
                        }
                    });
        });

    }

    /**
     * Try to re-login the user.
     */
    private reLogin(): Observable<string> {
        // obtain new authorization token and return it
    }
}
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // add authorization header with jwt token if available
        const currentUser = JSON.parse(sessionStorage.getItem('currentUser'));
        console.log('Interceter called');
        console.log(currentUser);
        //  const re = 'https://newsapi.org';
        const re = '/user';
        if (request.url.search(re) === -1) {

            if (currentUser && currentUser.token) {
                console.log('Token is being added....!!!!!');
                // console.log(currentUser.token);
                request = request.clone({
                    setHeaders: {
                        Authorisation: `Token ${currentUser.token}`,
                    }
                });
            }
            console.log('Request Sent :');
            console.log(request);
        }
        return next.handle(request);
    }
}
Related