Interceptors let you inspect and modify every HTTP request and response passing through HttpClient, ideal for cross-cutting concerns like authentication and logging. This lesson covers the modern functional interceptor API.
What Is an HTTP Interceptor?
An interceptor sits in the middle of every outgoing request and incoming response, letting you transform the request before it's sent, or the response (or error) before it reaches your application code, without touching every individual service method.
Modern Angular uses functional interceptors, plain functions matching the HttpInterceptorFn signature, registered with provideHttpClient(withInterceptors([...])).
req is the outgoing HttpRequest; requests are immutable, use .clone() to change anything.
next forwards the request to the next interceptor in the chain (or the actual HTTP call, if it's the last one).
The return value is an Observable of the eventual response, which you can further transform with RxJS operators.
Interceptors run in the order they're listed in withInterceptors([...]).
Interceptors Cheatsheet
Common interceptor tasks and their implementation pattern.
Task
Approach
Attach an auth token
Clone the request with an added Authorization header
Log every request/response
Wrap next(req) with tap() to log timing/status
Handle 401 globally
catchError checking error.status === 401, then redirect to login
Show a global loading spinner
Increment/decrement a shared loading counter around next(req)
Add a base URL to relative paths
Clone the request with a rewritten url
Register interceptors
provideHttpClient(withInterceptors([a, b, c]))
A Logging Interceptor
A logging interceptor is a good first example: it doesn't modify the request or response, only observes them as they pass through, useful for debugging or basic analytics.
An error-handling interceptor can catch specific HTTP status codes application-wide, redirecting to a login page on 401 Unauthorized, for example, without repeating that logic in every service.
Interceptors execute in the order listed in withInterceptors([...]) for the outgoing request, and in reverse order as the response travels back, similar to middleware chains in server frameworks.
Mutating req directly instead of using .clone(), which Angular's HttpRequest does not allow (requests are immutable).
Forgetting to call next(req) (or returning early without it), which silently drops the request entirely.
Attaching auth headers to every request indiscriminately, including calls to third-party or public endpoints that shouldn't receive your token.
Registering interceptors in the wrong order, causing an error-handling interceptor to run before the interceptor that would have retried or refreshed a token.
Key Takeaways
Interceptors intercept every outgoing request and incoming response through HttpClient.
Modern Angular uses functional interceptors registered via withInterceptors([...]).
Requests are immutable, use req.clone() to modify headers, URL, or body.
Interceptors are ideal for cross-cutting concerns: auth tokens, logging, and global error handling.
Pro Tip
Guard auth-token interceptors with a URL check (like only attaching a token to requests matching your own API's base URL), so you never accidentally leak an authorization header to a third-party service you also call via HttpClient.
You now understand HTTP interceptors. Next, learn dedicated Error Handling strategies for HTTP requests.