Refresh token inteceptor using NGRX

Viewed 1363

so I have created a refresh token http inteceptor, which looks for a 401 error from the API and then attempts to refresh the users token.

There are lot's of tutorials out there and plenty on here on how to handle token refreshing, however, a lot, if not all of them just use a service in the inteceptor, whereas, I would like to dispatch actions using NGRX.

My actions (see below) are simple, REFRESH_TOKEN triggers an effect which calls an API endpoint which will hopefully return a fresh token for the user (I have other effects for handling the success/fail of that action, redirect or save the data accordingly).

My first attempt at the inteceptor:

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        this.loaded$ = this.auth.pipe(select(selectAuthLoaded));
        this.loading$ = this.auth.pipe(select(selectAuthLoading));

        // @ts-ignore
        return next.handle(request).pipe(catchError(error => {
            if (error instanceof HttpErrorResponse && error.status === 401) {
                return this.handle401Error(request, next);
            } else {
                return throwError(error);
            }
        }));
    }

    private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
        this.loading$.subscribe(isLoading => {
            this.storage.getItem('refresh_token').subscribe(refreshToken => {
                if (!isLoading && refreshToken) {
                    this.auth.dispatch(new RefreshToken(refreshToken));
                } else {
                    return next.handle(request);
                }
            });
        });
    }

}

What I am thinking here is that if it's a 401, run the handle401ERror function. This firstly check's if the auth state is loaded, and get's the users refresh token from local storage (This is bad and it will be changed to a COOKIE once I get this nailed), if auth is loaded & there is a refresh token then dispach the REFRESH_TOKEN action.

This seems to result in the following error:

You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
1 Answers

I've run into this problem as well. Until I find a better solution, I have just tapped into the effect itself. I'm not sure if this qualifies as answer but here is the code I've used so far:

if (error.msg === 'invalid_token') {
  this.authService.dispatch(fromAuthStore.refreshToken());
  return this.authEffects.refreshTokenSuccess$.pipe(
    take(1),
    mergeMap(() => {
      return next.handle(this.setRequest(req));
    })
  );
} else {
  return throwError(error);
}

Hope this helps

edit: Here's a link that might give a little more explanation and provide alternatives. Basically, you end up listening to ngrx. https://netbasal.com/listening-for-actions-in-ngrx-store-a699206d2210

Related