angularjwtrefresh-tokenangular-http-interceptors

Calling api request inside an interceptor for jwt refresh token going to an infinite loop


I am trying to implement the the refresh jwt token mechanism in an interceptor.

I am following the accepted answer way in this post

Angular - Waiting for refresh token function to finish before forwarding the request

This is my code

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // add auth header with jwt if user is logged in and request is to api url
    const token = this.localStorageService.token;
    const isApiUrl = request.url.startsWith(environment.apiUrl);

    if (token && isApiUrl) {

        if (this.jwtHelperService.isTokenExpired(token)) {

            return from(this.refreshToken()).pipe(mergeMap((response) => {
                if (response) {
                    localStorage.setItem(LocalStorageKeys.TOKEN, JSON.stringify(response));
                    //localStorage.setItem(LocalStorageKeys.REFRESH_TOKEN, JSON.stringify(response.data.refreshToken));

                    request = request.clone({
                        setHeaders: {
                            Authorization: `Bearer ${response}`
                        }
                    });

                    return next.handle(request);
                }
                else {
                    this.authenticationService.logout();
                    return next.handle(request);
                }
            }
            ));
        }
        else {
            request = request.clone({
                setHeaders: {
                    Authorization: `Bearer ${token}`
                }
            });

            return next.handle(request);
        }
    }

    return next.handle(request);
}

async refreshToken(): Promise<string> {
    const res$ = this.http
        .post(`${environment.apiUrl}/authentication/refresh-token`,
            { token: this.localStorageService.token, refreshToken: this.localStorageService.refreshToken })
        .pipe(map((res) => res['data']['token']))
        .pipe(first());

    const response = await lastValueFrom(res$);
    return response;
}

But for me when the refresh token method is called it again goes to the interceptor and so making it go in an infinite loop.

What am I am doing wrong?


Solution

  • You should add a check to make sure the token isn't injected into the header when the endpoints is for authorization.

    const isAuthenticationEndpoint = request.url === `${environment.apiUrl}/authentication/refresh-token`
    if (token && isApiUrl && !isAuthenticationEndpoint)
    

    Otherwise it will try to inject the token in the header, realise there is not a (valid) token, try to get one thus causing the loop.