generated from nhcarrigan/template
feat: another security sweep
This commit is contained in:
@@ -4,36 +4,78 @@
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import {
|
||||
HttpRequest,
|
||||
HttpHandler,
|
||||
HttpEvent,
|
||||
HttpInterceptor,
|
||||
HttpErrorResponse
|
||||
HttpErrorResponse,
|
||||
HttpClient
|
||||
} from '@angular/common/http';
|
||||
import { Observable, catchError, throwError } from 'rxjs';
|
||||
import { Observable, catchError, throwError, switchMap, BehaviorSubject, filter, take } from 'rxjs';
|
||||
import { Router } from '@angular/router';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable()
|
||||
export class AuthInterceptor implements HttpInterceptor {
|
||||
constructor(private router: Router) {}
|
||||
private isRefreshing = false;
|
||||
private refreshTokenSubject = new BehaviorSubject<boolean | null>(null);
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private http: HttpClient
|
||||
) {}
|
||||
|
||||
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||
// Clone the request to add withCredentials
|
||||
// This ensures cookies are sent with every request
|
||||
const authReq = request.clone({
|
||||
withCredentials: true
|
||||
});
|
||||
|
||||
return next.handle(authReq).pipe(
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
if (error.status === 401) {
|
||||
// Unauthorized - redirect to home
|
||||
this.router.navigate(['/']);
|
||||
if (error.status === 401 && !request.url.includes('/auth/refresh') && !request.url.includes('/auth/logout')) {
|
||||
return this.handle401Error(authReq, next);
|
||||
}
|
||||
return throwError(() => error);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private handle401Error(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||
if (!this.isRefreshing) {
|
||||
this.isRefreshing = true;
|
||||
this.refreshTokenSubject.next(null);
|
||||
|
||||
return this.http.post(
|
||||
`${environment.apiUrl}/auth/refresh`,
|
||||
{},
|
||||
{ withCredentials: true }
|
||||
).pipe(
|
||||
switchMap(() => {
|
||||
this.isRefreshing = false;
|
||||
this.refreshTokenSubject.next(true);
|
||||
return next.handle(request);
|
||||
}),
|
||||
catchError((err) => {
|
||||
this.isRefreshing = false;
|
||||
this.refreshTokenSubject.next(false);
|
||||
this.router.navigate(['/']);
|
||||
return throwError(() => err);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return this.refreshTokenSubject.pipe(
|
||||
filter(result => result !== null),
|
||||
take(1),
|
||||
switchMap(success => {
|
||||
if (success) {
|
||||
return next.handle(request);
|
||||
}
|
||||
return throwError(() => new Error('Token refresh failed'));
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user