0

I have the 401 interceptor, when the access_token is expired, with a successfully case with one request. The interceptor reloads the token and it returns the next.handle(customReq). But I have a problem when 2 or more request at the same time and both request has expired tokens, because the second request try to refresh again, but now the refresh token is invalid. So.... I tried to set a flag to do it only once, and using a custom observable to return. The problem is the component never now if it was successfully or not, and I can't remove the loader.

the http interceptor:

    return next
        .handle(customReq).pipe(
        tap((ev: HttpEvent < any > ) => {
            if (ev instanceof HttpResponse) {
                this.setApiStatus(ApiStatusCode.ACTIVE);
                this.interceptorIgnore.removeIgnore(request.url);
            }
        }),
        catchError(resp => {
            if (resp instanceof HttpErrorResponse) {
                switch (true) {
                    // Unauthorized
                    case resp.status === 401:
                        return this.attemptToRefreshToken(apiRequest, customReq, next);
                    // More code unnecessary ....
                }
            }

            return throwError(resp);
        })
    );

attemptToRefreshToken method:

attemptToRefreshToken(apiRequest: ApiRequest, customReq: HttpRequest<any>, next: HttpHandler) {


        const retryRequest = () => {
            this.updatingToken = false;
            customReq = customReq.clone({
                headers: apiRequest.buildHeader()
            });
            return next.handle(customReq);
        };

        if (!this.updatingToken) {
            this.updatingToken = true;
            const tokenRequestData = this.apiAuth.refreshTokenData();
            return this.http.request(tokenRequestData.opts.method, tokenRequestData.url, tokenRequestData.opts)
            .pipe(flatMap((token: ResponseTokenFormat) => {
                ApiAuth.storedToken = token;
                this.usersService.queryUsersUsename(ApiAuth.storedUser).then(([user]) => {
                    if (user && !user.isAdmin) {
                        this.sessionService.setUserPermissions(user);
                    }
                });
                this.tokenUpdated.next();
                return retryRequest();
            }));
        }

        return this.tokenUpdated$.pipe(
            flatMap(() => retryRequest())
        );       

}

The retryRequest executes when the next() is invoked and works fine, but it never inform to service witch call this http request. The return retryRequest(); when I refresh the token works perfectly and the service can subscribe.

What I am doing wrong? Maybe the Observable?

1 Answer 1

0

I think you may have to use exhaustMap instead of flatMap, in attemptToRefreshToken.

How they work?

  • flatMap: creates an Observable immediately for any source item, all previous Observables are kept alive
  • exhaustMap: the source items are ignored while the previous Observable is not completed.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.