102 lines
2.6 KiB
TypeScript
102 lines
2.6 KiB
TypeScript
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<string | null>(null);
|
|
|
|
export const AuthInterceptor: HttpInterceptorFn = (
|
|
req: HttpRequest<unknown>,
|
|
next: HttpHandlerFn
|
|
): Observable<HttpEvent<unknown>> => {
|
|
|
|
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);
|
|
})
|
|
);
|
|
})
|
|
);
|
|
}; |