Search code examples
angularaccess-tokenangular-httpclientbearer-tokenangular-http-interceptors

Angular HttpInterceptor RangeError: Maximum call stack size exceeded


I have a problem with my HttpInterceptor calling many times in a short period that it results in an error: RangeError: Maximum call stack size exceeded.

My HttpInterceptor is intercepting every request to add a bearer token to the header. The first time it passes the intercepter it will get the token from the authentication server this results in many POST calls to the authenticator in a short time. I guess this is that when it has no bearer token in the header the interceptor will make a call with HttpClient resulting in passing true the interceptor again and keeps calling GetAuthToken() resulting in looping until the error kicks in.

I have tried to ignore the request with a flag in the header but it still keeps looping. Do you have any suggestions how to cover this issue?

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('INTERCEPTOR');
    // We retrieve the token, if any
    const token = this.GetAuthToken();
    let newHeaders = req.headers;
    if (token) {
       // If we have a token, we append it to our new headers
       newHeaders = newHeaders.append('Authorization', "bearer " + token);
    }
    // Finally we have to clone our request with our new headers
    // This is required because HttpRequests are immutable
    const authReq = req.clone({headers: newHeaders});
    // Then we return an Observable that will run the request
    // or pass it to the next interceptor if any
    return next.handle(authReq);
  }

  GetAuthToken(): any{
    if (localStorage.getItem('access_token') != null){
        return localStorage.getItem('access_token');
      }
    let httpHeaders = new HttpHeaders({
       'Content-Type' : 'application/x-www-form-urlencoded'
    });
    let options = {
      headers: httpHeaders
    };
    let body = `grant_type=${this.grant_type}&client_id=${this.client_id}&username=${this.username}&password=${this.password}`
    this._http.post<AuthResponse>(this.url, body, options).subscribe(result => {
      localStorage.setItem('access_token', result.access_token);
      localStorage.setItem('refresh_token', result.refresh_token);
      return result.access_token;
    });
  }

You see the console.log("INTERCEPTOR") many times from the interceptor method


Solution

  • your interceptor intercep all, even your call in GetAuthToken, you need use an "if" to skip the call from GetAuthToken

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.body==`grant_type=${this.grant_type}&client_id=${this.client_id}&username=${this.username}&password=${this.password}`)
              return next.handle(req);
    
        ...rest of your code..
      }
    

    You can also add a "fool header", like it's showed in this SO

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.headers.get("skip")){
          const newHeader=req.headers.delete("skip");
          const newreq= req.clone({headers: newHeaders});
          return next.handle(newreq);
        }
        ...rest of your code..
      }
    

    And in GetAuthToken()

    GetAuthToken(){
       ...
       let options = {
          headers: httpHeaders.Add("skip",true)
        };
       ...
    }