61 lines
2.2 KiB
TypeScript
61 lines
2.2 KiB
TypeScript
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
|
|
import { inject } from '@angular/core';
|
|
import { AuthService } from '../services/auth.service';
|
|
import { catchError, switchMap } from 'rxjs/operators';
|
|
import { throwError, of } from 'rxjs';
|
|
|
|
export const authInterceptor: HttpInterceptorFn = (req, next) => {
|
|
const auth = inject(AuthService);
|
|
|
|
// Attach Authorization header when we have a token
|
|
const token = auth.getAccessToken();
|
|
let authReq = req;
|
|
const isRefreshCall = req.url.includes('/auth/refresh');
|
|
const isApiCall = req.url.startsWith('/proxy/api') || req.url.startsWith('/api');
|
|
|
|
// Ensure cookies are sent for API calls (dev proxy and prod)
|
|
if (req.url.startsWith('/proxy/api') || req.url.startsWith('/api')) {
|
|
authReq = authReq.clone({ withCredentials: true });
|
|
}
|
|
|
|
if (token && isApiCall) {
|
|
authReq = authReq.clone({ setHeaders: { Authorization: `Bearer ${token}` } });
|
|
}
|
|
|
|
return next(authReq).pipe(
|
|
catchError((err) => {
|
|
if (!isApiCall) {
|
|
// Do not attempt refresh for non-API requests (e.g., YouTube/Twitch/Rumble)
|
|
return throwError(() => err);
|
|
}
|
|
if (err instanceof HttpErrorResponse && err.status === 401) {
|
|
// If the 401 is for the refresh endpoint itself, do NOT try to refresh again.
|
|
if (isRefreshCall) {
|
|
return throwError(() => err);
|
|
}
|
|
// If there is no access token at all, we are not logged in: do not try refresh
|
|
const hasToken = !!auth.getAccessToken();
|
|
if (!hasToken) {
|
|
return throwError(() => err);
|
|
}
|
|
// Try a single refresh then retry the request once
|
|
return auth.refresh().pipe(
|
|
switchMap((ok) => {
|
|
if (!ok) return throwError(() => err);
|
|
const newToken = auth.getAccessToken();
|
|
let retry = authReq;
|
|
if (newToken) {
|
|
retry = retry.clone({ setHeaders: { Authorization: `Bearer ${newToken}` } });
|
|
}
|
|
if (retry.url.startsWith('/proxy/api')) {
|
|
retry = retry.clone({ withCredentials: true });
|
|
}
|
|
return next(retry);
|
|
})
|
|
);
|
|
}
|
|
return throwError(() => err);
|
|
})
|
|
);
|
|
};
|