0

I am trying to call the MSAL silentTokenrefresh method from Angular authInterceptor whenever the 401 hits. And then i am trying to recall the failed request again with a new token so the service won't be interrupted. I have followed this stackoverflow link (answered by Andrei Ostrovski) and implemented the same in my application.

There are two problem with refreshToken() method.

  1. the catchError expects return variable where i put EMPTY. The code is happy, but it is NOT triggering back the failed request where the total purpose is not achieved. It means that whenever it encounters 401 and it is allowing to acquire the new token and then it is not triggering the failed requests.

enter image description here

  1. To resolve the above one, i just took another approach (instead of pipe, i used subscribed but there the return is not applicable) and then it became completely invalid.

enter image description here

Could you please suggest me here to make it work?

My complete authInterceptor file:

addAuthHeader(request) {
      const tokenType = "Bearer";
      const authHeader = this.sessionService.getAccessToken();
      if (authHeader) {
          return request.clone({
              setHeaders: {
                  "Authorization": tokenType + " "+ authHeader
              }
          });
      }
      return request;
  }

  refreshToken(): Observable<any> {
    if (this.refreshTokenInProgress) {
        return new Observable(observer => {
            this.tokenRefreshed$.subscribe(() => {
                observer.next();
                observer.complete();
            });
        });
    } else {
        this.refreshTokenInProgress = true;

        // Getting the scope.
        const loginRequest: { scopes: any } = {
          scopes: ['openId','profile'],
        };

        return this.msalAuthService.acquireTokenSilent(loginRequest).pipe(
          tap((payloadInfo)=>{
            this.authServices.setSessions(payloadInfo); 
            this.refreshTokenInProgress = false;
            this.tokenRefreshedSource.next();
          }),
          catchError(() => {
            this.refreshTokenInProgress = false;
            this.authServices.logout();
            return EMPTY;
          })
        )
    }
  }

  handleResponseError(error, request?, next?) {
    // Invalid token error
    if (error.status === 401) {
      return this.refreshToken().pipe(
        switchMap(() => {
          request = this.addAuthHeader(request);
          return next.handle(request);
        }),
        catchError(e => {
          if (e.status !== 401) {
              return this.handleResponseError(e);
          } else {
            this.authentiCationService.logout();
            this.router.navigate(["logout"], {
              replaceUrl: true
            });
          }
        }));
    }
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.totalRequests++;
    req = req.clone({ headers: req.headers.set("Accept", "*/*") });
    req = req.clone({
      headers: req.headers.set("Content-Type", "application/json")
    });
    req = this.addAuthHeader(req);
    const started = Date.now();

    return next.handle(req).pipe(
      tap(
        (event: HttpEvent<any>) => {
          if (event instanceof HttpResponse) {
            // some internal logic for the success scenario 
          }
        },
        (err: any) => {
          this.handleResponseError(err, req, next);
        }
      )
    );
  }
Raja
  • 3,477
  • 12
  • 47
  • 89

1 Answers1

0

The compile time error you are getting is because you are returning the Subscription instead of the Observable. Please take a look at the difference between them: https://angular.io/guide/observables

You have to return the Observable from your code. In catchError return Observable.throw(error.statusText);

Rutha
  • 751
  • 3
  • 7