All files / src/app/core/interceptors jwt.interceptor.ts

58.46% Statements 38/65
42.85% Branches 9/21
57.14% Functions 8/14
89.18% Lines 33/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 751x 1x 1x 1x 1x     1x       2x 4x 4x   4x     4x 1x     3x 1x     2x   2x 2x               2x 2x       2x 2x 2x   2x   2x 2x   1x 1x 1x 1x     1x 1x 1x 1x                            
import { HttpErrorResponse, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { SessionService } from '@core/services/session.service';
import { AuthService } from "@core/services/auth.service";
import { BehaviorSubject, catchError, filter, switchMap, take, throwError } from "rxjs";
import { SessionInformation } from "@core/model/session-information.interface";
import { ApiError } from "@core/errors/api-error";
import { ErrorProcessorService } from "@core/services/error-processor.service";
 
 
@Injectable({ providedIn: 'root' })
export class JwtInterceptor implements HttpInterceptor {
  private isRefreshing = false;
  private refreshTokenSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
 
  constructor(private sessionService: SessionService, private authService: AuthService, private errorProcessorService: ErrorProcessorService) {}
 
  public intercept(request: HttpRequest<unknown>, next: HttpHandler) {
    if (!this.sessionService.isLogged()) {
      return next.handle(request);
    }
 
    if(!request.url.match(/api\//)) {
      return next.handle(request);
    }
 
    return next.handle(request).pipe(
      catchError(error => {
        if (this.shouldTryToRefreshToken(request, error)) {
          return this.tryToRefreshToken(request, next);
        }
        return this.errorProcessorService.processError(error);
      })
    );
  }
 
  private shouldTryToRefreshToken(request: HttpRequest<unknown>, error: HttpErrorResponse) :boolean {
    console.log('shouldTryToRefreshToken?');
    return error instanceof HttpErrorResponse && error.status === 401 && !request.url.includes('auth/login') && !request.url.includes('auth/refresh-token')
  }
 
  private tryToRefreshToken(request: HttpRequest<unknown>, next: HttpHandler) {
    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(false);
 
      const isLogged = this.sessionService.isLogged();
 
      if (isLogged) {
        return this.authService.refreshToken().pipe(
          switchMap((data: SessionInformation) => {
            this.isRefreshing = false;
            this.sessionService.logIn(data);
            this.refreshTokenSubject.next(true);
            return next.handle(request);
          }),
          catchError((error: ApiError) => {
            this.isRefreshing = false;
            this.refreshTokenSubject.next(false);
            this.sessionService.logOut();
            return this.errorProcessorService.processError(error);
          })
        );
      }
    }
 
    // let's handle original request with the new token
    return this.refreshTokenSubject.pipe(
      filter(token => token !== false),
      take(1),
      switchMap(() => next.handle(request))
    );
  }
}