Only the api/authentication/reset-password
endpoint is not intercepted. Other endpoints and api/authentication/refresh-token
are intercepted via authInterceptor
as expected.
// srcappadmininterceptorauth.interceptor.ts
import { Routes } from '@angular/router';
import { AdminComponent } from './admin.component';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { serverErrorInterceptor } from './interceptor/server-error.interceptor';
import { AuthService } from './services/auth/auth.service';
export const ADMIN_ROUTES: Routes = [
{
path: '',
component: AdminComponent,
providers: [AuthService, provideHttpClient(withInterceptors([serverErrorInterceptor]))],
children: [
{
path: 'auth',
pathMatch: 'full',
loadComponent: () => import('./auth/auth.component').then((m) => m.AuthComponent),
title: 'Админ | Авторизация',
},
{
path: '',
loadChildren: () => import('./admin-shell/admin-shell.routes').then((m) => m.ADMIN_SHELL_ROUTES),
},
],
},
];
// srcappadminadmin-shelladmin-shell.routes.ts
import { Routes } from '@angular/router';
import { AdminShellComponent } from './admin-shell.component';
import { AuthGuard } from '../guards/auth.guard';
import { RoleEnum } from '../enums/role.enum';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { serverErrorInterceptor } from '../interceptor/server-error.interceptor';
import { authInterceptor } from '../interceptor/auth.interceptor';
//todo: refactor ./ and ../ paths. Also the canActivate with their data.
export const ADMIN_SHELL_ROUTES: Routes = [
{
path: '',
component: AdminShellComponent,
providers: [provideHttpClient(withInterceptors([serverErrorInterceptor, authInterceptor]))],
canActivate: [AuthGuard],
data: { permittedRoles: [RoleEnum.ADMIN, RoleEnum.SUB_ADMIN] },
title: 'Админ',
children: [
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{
path: 'dashboard',
loadComponent: () => import('./../pages/dashboard/dashboard.component').then((m) => m.DashboardComponent),
title: 'Админ - Главная',
},
{
path: 'users',
canActivate: [AuthGuard],
data: { permittedRoles: [RoleEnum.ADMIN] },
loadComponent: () => import('./../pages/users/users.component').then((m) => m.UsersComponent),
title: 'Админ - Пользователи',
},
{
path: 'orders',
loadComponent: () => import('./../pages/orders/orders.component').then((m) => m.OrdersComponent),
title: 'Админ - Заказы',
},
{
path: 'receipts',
loadComponent: () => import('../pages/receipts/receipts.component').then((m) => m.ReceiptsComponent),
title: 'Админ - Рецепты',
},
{
path: 'products',
loadComponent: () => import('./../pages/products/products.component').then((m) => m.ProductsComponent),
title: 'Админ - Продукты',
},
{
path: 'import-export',
canActivate: [AuthGuard],
data: { permittedRoles: [RoleEnum.ADMIN] },
loadComponent: () =>
import('./../pages/import-export/import-export.component').then((m) => m.ImportExportComponent),
title: 'Админ - Перенос данных',
},
{
path: 'advertisements',
canActivate: [AuthGuard],
loadComponent: () =>
import('../pages/advertisements/advertisements.component').then((m) => m.AdvertisementsComponent),
title: 'Админ - Реклама',
},
{
path: 'categories',
canActivate: [AuthGuard],
data: { permittedRoles: [RoleEnum.ADMIN] },
loadComponent: () => import('./../pages/categories/categories.component').then((m) => m.CategoriesComponent),
title: 'Админ - Категории',
},
{
path: 'reset-password',
canActivate: [AuthGuard],
loadComponent: () =>
import('../pages/reset-password/reset-password.component').then((m) => m.ResetPasswordComponent),
title: 'Админ - Сброс пароля',
},
],
},
];
srcappadmininterceptorauth.interceptor.ts
import { inject } from '@angular/core';
import { HttpErrorResponse, HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http';
import { BehaviorSubject, catchError, filter, Observable, switchMap, take, throwError } from 'rxjs';
import { AuthService } from '../services/auth/auth.service';
import { AuthResponse } from '../interfaces/auth-response';
import { InterceptorSkipHeader } from '../../constants/constants';
let isRefreshing = false;
const refreshTokenSubject: BehaviorSubject<string | null> = new BehaviorSubject<string | null>(null);
export function authInterceptor(request: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> {
console.log('auth interceptor');
const authService = inject(AuthService);
if (request.headers.has(InterceptorSkipHeader)) {
const headers = request.headers.delete(InterceptorSkipHeader);
return next(request.clone({ headers }));
}
if (authService.accessToken()) {
request = addToken(request, authService.accessToken()!);
}
function handle401Error(request: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> {
if (!isRefreshing) {
isRefreshing = true;
refreshTokenSubject.next(null);
return authService.refreshToken().pipe(
switchMap((response: AuthResponse) => {
isRefreshing = false;
refreshTokenSubject.next(response.accessToken);
return next(addToken(request, response.accessToken));
}),
catchError((error) => {
isRefreshing = false;
if (
error instanceof HttpErrorResponse &&
error.status === 401 &&
(error.error?.message === 'Token expired' || error.error?.message === 'Invalid token')
) {
authService.logOut();
}
return throwError(() => error);
}),
);
}
return refreshTokenSubject.pipe(
filter((token) => token !== null),
take(1),
switchMap((token) => next(addToken(request, token!))),
);
}
return next(request).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 401) {
return handle401Error(request, next);
}
return throwError(() => error);
}),
);
}
function addToken(request: HttpRequest<unknown>, token: string) {
return request.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
},
});
}
I also have tried to provide AuthService
to ADMIN_SHELL_ROUTES
providers but this creates to instances of AuthService
for ADMIN_ROUTES
and ADMIN_SHELL_ROUTES