UNPKG

ngx-auth

Version:

Angular 20+ Authentication module

142 lines (134 loc) 4.92 kB
import { HttpClient } from '@angular/common/http'; import { InjectionToken, signal, inject, makeEnvironmentProviders } from '@angular/core'; import { Subject, switchMap, catchError, from, first, map, throwError, combineLatest, tap } from 'rxjs'; import { Router } from '@angular/router'; /** * Essential service for authentication */ class NgxAuthService { } const AUTH_SERVICE = new InjectionToken('ngx-auth--service'); const NgxRefreshInProgress = signal(false, ...(ngDevMode ? [{ debugName: "NgxRefreshInProgress" }] : [])); const delay$ = new Subject(); const ngxAuthInterceptor = (req, next) => { const authService = inject(AUTH_SERVICE); const http = inject(HttpClient); if (authService.skipRequest(req)) { return next(req); } const request$ = NgxRefreshInProgress() ? delayRequest(authService, req) : addToken(authService, req); return request$.pipe(switchMap(req => next(req)), catchError(res => responseError(authService, http, req, res))); }; /** * Add access token to headers or the request */ function addToken(authService, req) { return from(authService.getAccessToken()) .pipe(first(), map(token => { if (token) { return req.clone({ setHeaders: authService.getHeaders?.(token) ?? { Authorization: `Bearer ${token}` }, }); } return req; })); } /** * Delay request, by subscribing on refresh event, once it finished, process it * otherwise throw error */ function delayRequest(authService, req) { return delay$.pipe(first(), switchMap(canDelay => canDelay ? addToken(authService, req) : throwError(() => req))); } /** * Failed request interceptor, check if it has to be processed with refresh */ function responseError(authService, http, req, res) { const refreshShouldHappen$ = authService.refreshShouldHappen(res, req); return combineLatest([ from(typeof refreshShouldHappen$ === 'boolean' ? Promise.resolve(refreshShouldHappen$) : refreshShouldHappen$), from(authService.isAuthenticated()), ]) .pipe(switchMap(([refreshShouldHappen, isAuthenticated]) => { if (refreshShouldHappen && isAuthenticated && !NgxRefreshInProgress()) { NgxRefreshInProgress.set(true); from(authService.refreshToken()) .subscribe({ error: () => { NgxRefreshInProgress.set(false); delay$.next(false); }, next: () => { NgxRefreshInProgress.set(false); delay$.next(true); }, }); } if (refreshShouldHappen && isAuthenticated && NgxRefreshInProgress()) { return delay$.pipe(first(), switchMap(canRetry => canRetry ? http.request(req) : throwError(() => res || req))); } return throwError(() => res); })); } const PUBLIC_REDIRECT_URI = new InjectionToken('ngx-auth--public-redirect-uri'); /** * Guard, checks access token availability and allows or disallows access to page, * and redirects out */ const ngxProtectedGuard = (_, state) => { const authService = inject(AUTH_SERVICE); const publicUri = inject(PUBLIC_REDIRECT_URI); const router = inject(Router); return from(authService.isAuthenticated()).pipe(tap(async (isAllowed) => { if (isAllowed) { return; } authService.setInterruptedUrl?.(state.url); await router.navigateByUrl(publicUri); })); }; const PROTECTED_REDIRECT_URI = new InjectionToken('ngx-auth--protected-redirect-uri'); /** * Guard, checks access token availability and allows or disallows access to page, * and redirects out */ const ngxPublicGuard = () => { const authService = inject(AUTH_SERVICE); const protectedUri = inject(PROTECTED_REDIRECT_URI); const router = inject(Router); return from(authService.isAuthenticated()).pipe(map(isAuthenticated => !isAuthenticated), tap(async (isAllowed) => { if (isAllowed) { return; } await router.navigateByUrl(protectedUri); })); }; function provideNgxAuthProviders(options) { return makeEnvironmentProviders([ { provide: AUTH_SERVICE, useExisting: options.authService, }, { provide: PROTECTED_REDIRECT_URI, useValue: options.protectedRedirectUri, }, { provide: PUBLIC_REDIRECT_URI, useValue: options.publicRedirectUri, }, ]); } /** * Generated bundle index. Do not edit. */ export { AUTH_SERVICE, NgxAuthService, NgxRefreshInProgress, PROTECTED_REDIRECT_URI, PUBLIC_REDIRECT_URI, ngxAuthInterceptor, ngxProtectedGuard, ngxPublicGuard, provideNgxAuthProviders }; //# sourceMappingURL=ngx-auth.mjs.map