Here is the error it givesI'm getting Maximum Call stack size while debugging the code. I think it is stuck in the infinite loop, but I could not fix it. What should I do? .......................................................................................................................................................................................................................................................................................................... @Injectable() export class HttpAuthInterceptor implements HttpInterceptor {

  private autoAppendHeadersDefault = true;
  private refreshObservable: Observable<HttpEvent<any>> = null;
  private refreshSubsCount = 0;

  constructor(
    private storageService: StorageService,
    private appState: AppService,
    private http: HttpClient
  ) {
    this.autoAppendHeadersDefault = this.appState.hoodConfig.HTTP_AUTO_APPEND_HEADERS;
  }

  intercept(request: HttpRequest<any>, next: HttpHandler, disableTryFix = false): Observable<HttpEvent<any>> {

    let assetRequest = false;
    if (request.url.startsWith('/assets')) {
      assetRequest = true;
    }

    const newHeaders = {'Cache-Control': 'public, max-age=45',
      'Expires': new Date(new Date().getTime() + 45 * 60 * 1000).toLocaleString()
    }

    ;

    if (!assetRequest && this.appState.hoodConfig.HTTP_AUTO_APPEND_HEADERS) {
      // append aToken || gToken
      let token = this.storageService.get('aToken');
      if ('undefined' === typeof token || !token) {
        token = this.storageService.get('gToken');
      }

      if ('undefined' !== typeof token && token) {
        newHeaders['Authorization'] = `Bearer ${token}`;
      } else {
        // neither aToken nor gToken are set
        if (disableTryFix) {
          this.removeAllTokens();
          return observableThrowError({error: 'Can\'t reauth: 01'});
        }

        return this.tryFixAuth(next).pipe(flatMap(
          (res: any) => {
            this.storageService.set('gToken', res.access_token);

            request = request.clone({
              setHeaders: newHeaders

            });

            return this.intercept(request, next, true);

          }
        ));
      }
      // headers appended to every request
      if (!request.headers.get('Content-Type')) {

        newHeaders['Content-Type'] = 'application/json';
      }
    }
    this.appState.hoodConfig.HTTP_AUTO_APPEND_HEADERS = this.autoAppendHeadersDefault;

    request = request.clone({
      setHeaders: newHeaders

    });

    return next.handle(request).pipe(catchError((err: any, caught: Observable<HttpEvent<any>>) => {
      if (!(err instanceof HttpErrorResponse)) {
        return caught;
      }

      const error = err.error;

      if (error.status === 401) {

        if (disableTryFix) {
          this.removeAllTokens();
          this.navigateOnAuthFail();
          return observableThrowError({error: 'Can\'t reauth: 02'});
        }

        return this.tryFixAuth(next).pipe(flatMap(
          (res: any) => {
            --this.refreshSubsCount;

            if ('undefined' !== typeof res.refresh_token) {
              // got aToken & refresh_token
              this.storageService.set('aToken', res.access_token);
              this.storageService.set('refresh_token', res.refresh_token);
            } else if ('undefined' !== typeof res.access_token) {
              // got only gToken
              this.storageService.set('gToken', res.access_token);
            } else {
              console.log('tryFix: nothing useful returned')
              // got no aToken, no gToken, no refresh_token
            }

            // retry request
            return this.intercept(request, next, true);

          }
        ));
      }

      if (disableTryFix && error.status === 400 && error.url.endsWith('oauth/v2/token')) {
        if (!environment.production) {
          console.log('Invalid refresh token (400)');
        }
        this.storageService.remove('refresh_token');
        this.storageService.remove('aToken');
        this.navigateOnAuthFail();
      }

      if (disableTryFix && error.status === 403) {
        const errorObj = error;
        // Server requires aToken but gToken was sent
        if (errorObj.message == 'Access Denied.') {
          if (!environment.production) {
            console.log('No token');
          }
          this.navigateOnAuthFail();
        }
      }

      return observableThrowError(error);
    }));
  }

  private tryFixAuth(next: HttpHandler): Observable<any> {
    if (!this.refreshObservable) {
      if (!environment.production) {
        console.log('Fixing auth');
      }
    }

    if (this.storageService.get('refresh_token')) {
      return this.refreshToken(next);
    } else if (this.storageService.get('aToken')) {
      // no refresh_token, but aToken
      // since aToken is dead it's not useful
      this.storageService.remove('aToken');
    } else {

      return this.guestToken();
    }
  }

  private refreshToken(next: HttpHandler): Observable<any> {

    if (this.refreshObservable != null && this.refreshSubsCount > 0) {
      // if refreshSubsCount == 0 it means observable has worked for all subscribers and contains outdated request
      ++this.refreshSubsCount;
      return this.refreshObservable;
    } else if (this.refreshSubsCount <= 0) {
      this.refreshObservable = null;
    }

    const refreshToken = this.storageService.get('refresh_token');

    if ('undefined' === typeof refreshToken || !refreshToken || refreshToken == 'undefined') {
      this.storageService.remove('refresh_token');
      return observableThrowError({error: 'Refresh token is not set'});
    }

    const headers = new HttpHeaders();
    headers.append('Authorization', `Bearer ${this.storageService.get('gToken')}`);
    headers.append('Content-Type', 'application/json');

    const url = `${this.appState.config.WEBSITE_ENDPOINT}/oauth/v2/token`;
    const localData = {
      'client_id': this.appState.config.CLIENT_ID,
      'client_secret': this.appState.config.CLIENT_SECRET,
      'grant_type': 'refresh_token',
      'refresh_token': refreshToken
    };

    this.appState.hoodConfig.HTTP_AUTO_APPEND_HEADERS = false;

    this.refreshObservable = this.intercept(
      new HttpRequest<any>(
        'POST',
        url,
        localData,
        {
          headers: headers
        }
      ),
      next, true).pipe(
        share(),
        filter((event: HttpEvent<any>): boolean => event instanceof HttpResponse),
        map((event: HttpResponse<any>): any => event.body)
      );

    ++this.refreshSubsCount;
    return this.refreshObservable;
  }

  private guestToken(): Observable<any> {
    const url = `${
      this.appState.config.WEBSITE_ENDPOINT}/oauth/v2/token?client_id=${
      this.appState.config.CLIENT_ID}&client_secret=${
      this.appState.config.CLIENT_SECRET}&grant_type=client_credentials`;
    this.appState.hoodConfig.HTTP_AUTO_APPEND_HEADERS = false;
    return this.http.get<any>(url);
  }


  private navigateOnAuthFail() {
    console.warn('Page is going to be refreshed');


    window.location.reload();
  }

  private removeAllTokens() {
    this.storageService.remove('aToken');
    this.storageService.remove('gToken');
    this.storageService.remove('refresh_token');
  }
}

0 Answers