import { Injectable } from '@angular/core'; import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpErrorResponse, } from '@angular/common/http'; import { Observable, throwError, BehaviorSubject } from 'rxjs'; import { catchError, switchMap, filter, take, finalize } from 'rxjs/operators'; // Import finalize import { AuthService } from './auth.service'; @Injectable() export class JwtInterceptor implements HttpInterceptor { private isRefreshing = false; // Initialize refreshTokenSubject with null private refreshTokenSubject: BehaviorSubject = new BehaviorSubject(null); constructor(private authService: AuthService) {} intercept( request: HttpRequest, next: HttpHandler ): Observable> { if (request.url.includes('/auth/refresh')) { return next.handle(request); } const accessToken = this.authService.getAccessToken(); if (accessToken) { request = this.addToken(request, accessToken); } return next.handle(request).pipe( catchError((error) => { if (error instanceof HttpErrorResponse && error.status === 401) { return this.handle401Error(request, next); } return throwError(() => error); }) ); } private handle401Error(request: HttpRequest, next: HttpHandler): Observable { if (!this.isRefreshing) { this.isRefreshing = true; // Reset the refreshTokenSubject to null so that subsequent requests will wait // this.refreshTokenSubject.next(null); this.refreshTokenSubject = new BehaviorSubject(null); return this.authService.refreshToken().pipe( switchMap((token: any) => { this.refreshTokenSubject.next(token.accessToken); return next.handle(this.addToken(request, token.accessToken)); }), catchError((err) => { // If refresh fails, logout the user this.authService.clientSideLogout(); return throwError(() => err); }), finalize(() => { // When the refresh attempt completes, set isRefreshing to false this.isRefreshing = false; }) ); } else { // If a refresh is already in progress, wait for it to complete return this.refreshTokenSubject.pipe( filter(token => token != null), take(1), switchMap(jwt => next.handle(this.addToken(request, jwt))) ); } } private addToken(request: HttpRequest, token: string) { return request.clone({ setHeaders: { Authorization: `Bearer ${token}`, }, }); } }