import type { HttpEvent, HttpHandler, HttpHandlerFn, HttpInterceptor, HttpInterceptorFn, HttpRequest, } from '@ngify/http'; import { Injectable, inject } from '@outposts/injection-js'; import type { Observable } from 'rxjs'; import { AuthStateService } from '../auth-state/auth-state.service'; import { ConfigurationService } from '../config/config.service'; import { LoggerService } from '../logging/logger.service'; import { flattenArray } from '../utils/collections/collections.helper'; import { ClosestMatchingRouteService } from './closest-matching-route.service'; @Injectable() export class AuthInterceptor implements HttpInterceptor { private readonly authStateService = inject(AuthStateService); private readonly configurationService = inject(ConfigurationService); private readonly loggerService = inject(LoggerService); private readonly closestMatchingRouteService = inject( ClosestMatchingRouteService ); intercept( req: HttpRequest, next: HttpHandler ): Observable> { return interceptRequest(req, next.handle, { configurationService: this.configurationService, authStateService: this.authStateService, closestMatchingRouteService: this.closestMatchingRouteService, loggerService: this.loggerService, }); } } export function authInterceptor(): HttpInterceptorFn { const deps = { configurationService: inject(ConfigurationService), authStateService: inject(AuthStateService), closestMatchingRouteService: inject(ClosestMatchingRouteService), loggerService: inject(LoggerService), }; return (req, next) => { return interceptRequest(req, next, deps); }; } function interceptRequest( req: HttpRequest, next: HttpHandlerFn, deps: { authStateService: AuthStateService; configurationService: ConfigurationService; loggerService: LoggerService; closestMatchingRouteService: ClosestMatchingRouteService; } ): Observable> { if (!deps.configurationService.hasAtLeastOneConfig()) { return next(req); } const allConfigurations = deps.configurationService.getAllConfigurations(); const allRoutesConfigured = allConfigurations.map( (x) => x.secureRoutes || [] ); const allRoutesConfiguredFlat = flattenArray(allRoutesConfigured); if (allRoutesConfiguredFlat.length === 0) { deps.loggerService.logDebug( allConfigurations[0], 'No routes to check configured' ); return next(req); } const { matchingConfig, matchingRoute } = deps.closestMatchingRouteService.getConfigIdForClosestMatchingRoute( req.url, allConfigurations ); if (!matchingConfig) { deps.loggerService.logDebug( allConfigurations[0], `Did not find any configured route for route ${req.url}` ); return next(req); } deps.loggerService.logDebug( matchingConfig, `'${req.url}' matches configured route '${matchingRoute}'` ); const token = deps.authStateService.getAccessToken(matchingConfig); if (!token) { deps.loggerService.logDebug( matchingConfig, `Wanted to add token to ${req.url} but found no token: '${token}'` ); return next(req); } deps.loggerService.logDebug( matchingConfig, `'${req.url}' matches configured route '${matchingRoute}', adding token` ); req = req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`), }); return next(req); }