Add Auth Headers, Log, or Retry — Globally
HTTP Interceptors
A functional interceptor sees every outgoing HTTP request and incoming response — perfect for auth, logging, and error handling.
What you'll learn
- Write an HttpInterceptorFn
- Register interceptors with withInterceptors
- Attach an auth token and handle 401 responses
An interceptor is a function that sits between your code and the network. It can transform the outgoing request, inspect the response, retry, or short-circuit entirely.
A simple auth interceptor
import { inject } from '@angular/core';
import { HttpInterceptorFn } from '@angular/common/http';
import { AuthService } from './auth.service';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const token = inject(AuthService).token();
if (!token) return next(req);
const authed = req.clone({
setHeaders: { Authorization: `Bearer ${token}` },
});
return next(authed);
}; HttpRequest is immutable — clone with setHeaders instead of mutating.
Register
// app.config.ts
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { authInterceptor } from './auth.interceptor';
export const appConfig = {
providers: [
provideHttpClient(withInterceptors([authInterceptor])),
],
}; Handle errors and retries
Interceptors are also the natural place for global error handling.
import { catchError, throwError } from 'rxjs';
import { HttpErrorResponse } from '@angular/common/http';
import { Router } from '@angular/router';
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
const router = inject(Router);
return next(req).pipe(
catchError((err: HttpErrorResponse) => {
if (err.status === 401) router.navigate(['/login']);
return throwError(() => err);
}),
);
}; Chaining
You can pass multiple interceptors to withInterceptors. They run in array order on the way out and reverse order on the way back.
provideHttpClient(withInterceptors([authInterceptor, errorInterceptor, logInterceptor]))