import { inject } from '@angular/core'; import { HttpRequest, HttpHandlerFn, HttpEvent, HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http'; import { BehaviorSubject, catchError, filter, Observable, switchMap, take, throwError } from 'rxjs'; import { AuthService } from '../auth/auth.service'; let refreshInProgress = false; const refreshSubject = new BehaviorSubject(null); export const AuthInterceptor: HttpInterceptorFn = ( req: HttpRequest, next: HttpHandlerFn ): Observable> => { const authSvc: AuthService = inject(AuthService); let headers = req.headers; // add API key const apiKey = authSvc.getApiKey(); if (apiKey) { headers = headers.set('XApiKey', apiKey); } // add content type if needed if (!(req.body instanceof FormData) && (req.method === 'POST' || req.method === 'PUT') && !headers.has('Content-Type')) { headers = headers.set('Content-Type', 'application/json'); } // add access token const token = authSvc.currentToken; if (token) { headers = headers.set('Authorization', `Bearer ${token}`); } // final cloned request const clonedRequest = req.clone({ headers, withCredentials: true }); return next(clonedRequest).pipe( catchError((err: HttpErrorResponse) => { if (err.status !== 401) { return throwError(() => err); } // if refresh is already in progress if (refreshInProgress) { return refreshSubject.pipe( filter(t => t !== null), take(1), switchMap(newToken => { const retryReq = clonedRequest.clone({ headers: clonedRequest.headers.set('Authorization', `Bearer ${newToken}`), withCredentials: true }); return next(retryReq); }) ); } // start refresh refreshInProgress = true; refreshSubject.next(null); return authSvc.refreshToken()!.pipe( switchMap(res => { refreshInProgress = false; const newToken = res.accessToken; authSvc.safeSetToken(newToken); refreshSubject.next(newToken); const retryReq = clonedRequest.clone({ headers: clonedRequest.headers.set('Authorization', `Bearer ${newToken}`), withCredentials: true }); return next(retryReq); }), catchError(refreshErr => { refreshInProgress = false; refreshSubject.next(null); authSvc.logout(); return throwError(() => refreshErr); }) ); }) ); };