javascript / intermediate
Snippet
Token Refresh HttpInterceptor with Reactive Error Handling
Functional HTTP interceptors in Angular secure outgoing requests and manage authorization lifecycles. When encountering a 401 Unauthorized status, the interceptor pauses the original request stream, calls an asynchronous token refresh pipeline, and replays the failed request with updated credentials. If the refresh attempt fails, catchError invokes forced logout and safely propagates the terminal error.
snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';import { inject } from '@angular/core';import { catchError, switchMap, throwError } from 'rxjs';import { AuthService } from './auth.service';export const authRefreshInterceptor: HttpInterceptorFn = (req, next) => {const authService = inject(AuthService);return next(req).pipe(catchError((error: unknown) => {if (error instanceof HttpErrorResponse && error.status === 401 && !req.url.includes('/auth/refresh')) {return authService.refreshToken().pipe(switchMap(newToken => {const secureReq = req.clone({setHeaders: { Authorization: `Bearer ${newToken}` }});return next(secureReq);}),catchError(refreshErr => {authService.forceLogout();return throwError(() => refreshErr);}));}return throwError(() => error);}));};
angular
Breakdown
1
export const authRefreshInterceptor: HttpInterceptorFn = (req, next) => {
Defines a functional interceptor utilizing dependency injection via inject() without class boilerplate.
2
if (error instanceof HttpErrorResponse && error.status === 401 && !req.url.includes('/auth/refresh')) {
Filters for 401 Unauthorized responses while preventing infinite loops on the refresh endpoint itself.
3
const secureReq = req.clone({ setHeaders: { Authorization: `Bearer ${newToken}` } });
Clones the immutable HttpRequest object to attach the newly acquired Bearer authentication token.