lostintranslation
lostintranslation

Reputation: 24583

Replay a failed request with new token

I am trying to replay a failed request once a token has been refreshed. Following this as a guide.

My http interceptor:

isRefreshingToken: boolean = false
tokenSubject: Subject<void> = new Subject<void>()

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  return next.handle(this.tokenRequest(req)).pipe(
    catchError((error) => {
      if (error instanceof HttpErrorResponse) {
        if (error.status === HttpStatusCode.Unauthorized) {
          if (!this.isRefreshingToken) {
            this.isRefreshingToken = true
            this.dialog.open(LoginDialog).afterClosed().subscribe(() => {
              // at this point there is a new token in my token service
              this.isRefreshingToken = false
              this.tokenSubject.next()
            })
          }
          
          return this.tokenSubject.pipe(
            switchMap(() => {
              return next.handle(this.tokenRequest(req))
            })
          )
        }
      }

      return throwError(() => error)
    })
  )
}

tokenRequest(req: HttpRequest<any>): HttpRequest<any> {
  const token = // get token from service
  return req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`) });
}

This is working in that after logging in via a dialog the request that failed is replayed. However the subscribe is never firing from the client that made the original request.

return forkJoin({
  stuff: httpService.getStuff(),
  other: httpService.getOther(),
  ...
}).subscribe(() => {
  // won't trigger unless both stuff and other complete
})

So it would seem that the observable that I return from the http interceptor is incorrect in the case of an error and token refresh. Any ideas?

Upvotes: 1

Views: 58

Answers (1)

lostintranslation
lostintranslation

Reputation: 24583

My issue was with using forkJoin. I have updated the question to reflect that. Seems I misunderstood forkJoin in that all observables need to emit AND complete. Once I fixed that I was good. No issues with my interceptor.

combineLatest(
  httpService.getStuff(),
  httpService.getOther(),
)
.pipe(
  take(1),
)
.subscribe() => {
  // works
});

Upvotes: 0

Related Questions