1

I'm trying to get RefreshToken before each request and if it has expired I need to refresh it. The interceptor calls the service's function but I never get the API call. Please help

my interceptor code

public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!this.authService.isAccessTokenExpired()) {
      return next.handle(this.addCookiesToRequest(request));
    }
    if (this.refreshTokenInProgress) {
      return this.refreshTokenSubject.pipe(
        filter(result => result !== null),
        take(1),
        switchMap(() => next.handle(this.addCookiesToRequest(request)))
      );
    } else {
      this.refreshTokenInProgress = true;
      this.refreshTokenSubject.next(null);
      return this.authService.refreshExpiredToken().pipe(
        switchMap((token: any) => {
          this.refreshTokenInProgress = false;
          this.refreshTokenSubject.next(token);
          return next.handle(this.addCookiesToRequest(request));
        }),
        catchError((error: any) => {
          this.refreshTokenInProgress = false;
          return Observable.throw(error);
        })
      );
    }
  }
}

  public addCookiesToRequest(request: HttpRequest<any>): HttpRequest<any> {
    return request.clone({
      withCredentials: true
    });
  }

authService refreshToken code

refreshExpiredToken() {
    return this.http.get(`${api_url}/token/refresh`, {
      withCredentials: true,
      observe: 'response'
    }).pipe(
      tap((res) => {
        if (res.status >= 300 && res.status < 400) {
          window.location.href = res.url;
        }
      }),
      catchError((error) => {
        if (error.status === 401) {
          this.router.navigate(['/login']);
        }
        return of(error);
      })
    );
  }

I even tried to add somewhere .subscribe(), but still nothing

2 Answers 2

1

So the problem was that I didn't exclude the refreshToken URL from interceptor, that is why it was intercepting itself in an infinite loop, that is why it was never actually called.

Sign up to request clarification or add additional context in comments.

Comments

0

I think that the underlying problem is that you want to handle the referesh token state clent-side.

Aside from that, in your code your second if statement relies on the else statement: when refreshTokenInProgress is true the interceptor returns refreshTokenSubject, which will emit some value only in the else statement. In this way

 switchMap(() => next.handle(this.addCookiesToRequest(request)))

will never be triggered.

4 Comments

the problem is not with that line. I get to the return this.authService.refreshExpiredToken().pipe( line and then nothing happens, neither switchMap, nor catchError, because the http request for refreshToken never fires. But th service's function is being called and debugger goes into it.
And what do you mean by handling in client-side? I'm making a request to server to get new token
If I understood your code correctly, you return an observable that never emits values, that's why the return statement works but you don't get any value. The lines you should check are this.refreshTokenSubject.next(token); and this.refreshTokenSubject.next(null);.
this is not the case. Also that line that you write about is for other requests if they fired while the first one didn't fire yet because it is waiting for the refteshToken. And when refreshToken is refreshed - all the other requests will fire too

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.