jsmin
jsmin

Reputation: 392

How to call HTTP request while getting the response of another one in Angular7?

The case is when calling a service in the back-end and if I get error code indicates that it’s expired then in front-end First : request a valid jwt token. Second: rerequest the original http request after getting a valid token. The first step is done successfully but it’s not the case in the second one. This is the code in the interceptor

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {


    if (!request.url.endsWith('login') && !request.url.endsWith('refreshtoken')) {
      request = this.addAuthenticationToken(request);
    }
    return next.handle(request).pipe(catchError(err => {
      Log.log("Error Status: " + err.status);
      // invalid token or bad request
      if (err.status == this.NOT_VALID_TOKEN_OR_BAD_REQUEST_ERROR_CODE) {
        this.authenticationService.logOut();
        return EMPTY;
      }
      else if (err.status == this.TOKEN_EXPIRED_ERROR_CODE) { // token is expired
        this. doRefreshToken(request, next);
      }
    }
    ));
  }

doRefreshToken(request, next) {
    return this.authenticationService.refreshToken().subscribe((resp: HttpResponse<any>) => {
      Log.log("in subscripe refresh token")
      Log.log(resp.headers.get(this.AUTH_HEADER));
      StorageManagementUtil.setLocaltStorage(resp.headers.get(this.AUTH_HEADER), <PortalRsponseTransaction>resp.body);
    },
      (error) => { Log.log(error) },
      () => {
        Log.log("on complete()")
        request = this.addAuthenticationToken(request);
        return next.handle(request);
      });
  }

And this is refresh token service

refreshToken() {
    let map = new TSMap();
    map.set(this.RQUEST_BODY_KEY_SESSION_TOKEN, StorageManagementUtil.readFromLocalStorage(StorageManagementUtil.SESSION_TOKEN));
    var requsetBody = JSON.stringify(map.toJSON());
    let request = new PortalRequestTransaction(requsetBody);
    return this.http.post<PortalRsponseTransaction>(fullURL, request, {
      observe: 'response',
      responseType: 'json'
    });
  }

And this is a screenshot from network tap while inspecting

https://i.ibb.co/vqLTLh2/1.png

The question is why recalling the original service is not done after getting refresh token? And why calling service is done twice? (if we ignore the ones of OPTIONS request-type).

I'm beginner in angular so I wish I could provide sufficient information to figure out the problem.

Upvotes: 0

Views: 87

Answers (2)

jsmin
jsmin

Reputation: 392

This solution is inspired by this answer using switchMap

 intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!request.url.endsWith('login') && !request.url.endsWith('refreshtoken')) {
      request = this.addAuthenticationToken(request);
    }
    return next.handle(request).pipe(
      catchError((err) => {
        // invalid token or bad request
        if (err.status == this.NOT_VALID_TOKEN_OR_BAD_REQUEST_ERROR_CODE) {
          this.authenticationService.logOut();
          return EMPTY;
        }
        else if (err.status == this.TOKEN_EXPIRED_ERROR_CODE) {
          return this.handleRefreshToken(request, next);
        }
      })
    );
  }


  handleRefreshToken(request: HttpRequest<any>, next: HttpHandler) {

    return this.authenticationService.refreshToken().pipe(
      switchMap((tokenResp) => {
        StorageManagementUtil.setLocaltStorage(tokenResp.headers.get(this.AUTH_HEADER), <PortalRsponseTransaction>tokenResp.body);
        request = this.addAuthenticationToken(request);
        return next.handle(request);
      }),
      catchError(error => {
        if (error.status == this.NOT_VALID_TOKEN_OR_BAD_REQUEST_ERROR_CODE) {
          this.authenticationService.logOut();
          return EMPTY;
        }
      })
    );
  }

Upvotes: 0

Ankii32
Ankii32

Reputation: 106

1) 401 means unauthorized, it seems you are not sending the correct authorization header( Bearer {JWT-Token} ) in the request.

2) For refresh token, better use rxjs-retry , which will help you to handle refresh logic either on error or on expiry

Code follows:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {


    if (!request.url.endsWith('login') && !request.url.endsWith('refreshtoken')) {
      request = this.addAuthenticationToken(request);
    }
    return next.handle(request).pipe(
    retryWhen(err => {
     if (err.status == this.TOKEN_EXPIRED_ERROR_CODE) { // token is expired
       return this. doRefreshToken(request, next);
      }
    }),
    catchError(err => {
      Log.log("Error Status: " + err.status);
      // invalid token or bad request
      if (err.status == this.NOT_VALID_TOKEN_OR_BAD_REQUEST_ERROR_CODE) {
        this.authenticationService.logOut();
        return EMPTY;
      }
      else if (err.status == this.TOKEN_EXPIRED_ERROR_CODE) { // token is expired
        this. doRefreshToken(request, next); // return an observable
      }
    }
    ));
  }

The above code snippet, will hit retry if there is an error, it will first refresh token, return an observable, then calls again the getAll.

Upvotes: 0

Related Questions