In Angular, the standard way to automatically attach a JWT to every outgoing API request is an HTTP interceptor.
For modern standalone Angular, a functional interceptor is a clean approach.
1. Store the JWT after login
For example:
localStorage.setItem('access_token', response.token);
For production security, token storage strategy should be chosen carefully. This example uses
localStoragesimply to demonstrate interceptor behavior.
2. Create a JWT interceptor
jwt-interceptor.ts
import { HttpInterceptorFn } from '@angular/common/http';
export const jwtInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem('access_token');
if (token) {
const clonedRequest = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next(clonedRequest);
}
return next(req);
};
The important part is:
Authorization: `Bearer ${token}`
Angular will now send:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
3. Register the interceptor
In standalone Angular:
app.config.ts
import { ApplicationConfig } from '@angular/core';
import {
provideHttpClient,
withInterceptors
} from '@angular/common/http';
import { jwtInterceptor } from './interceptors/jwt-interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withInterceptors([
jwtInterceptor
])
)
]
};
Now you do not need to manually add the JWT in every service.
4. Your service remains simple
product-service.ts
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ProductService {
private http = inject(HttpClient);
getProducts() {
return this.http.get(
'https://localhost:7001/api/products'
);
}
}
You don't write:
headers: {
Authorization: `Bearer ${token}`
}
The interceptor handles it automatically.
Complete Flow
User Login
↓
ASP.NET Core validates credentials
↓
ASP.NET Core returns JWT
↓
Angular stores JWT
↓
ProductService
↓
HttpClient.get()
↓
JWT Interceptor
↓
Reads JWT
↓
Clones request
↓
Adds Authorization header
↓
ASP.NET Core Web API
Authorization: Bearer <JWT>
For example, Angular code:
this.http.get('/api/products');
effectively becomes:
GET /api/products
Authorization: Bearer eyJhbGciOi...
Why req.clone()?
Angular HttpRequest objects are immutable.
Therefore, you shouldn't modify the original request:
req.headers.set(...)
Instead:
const clonedRequest = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
Then continue the HTTP pipeline:
return next(clonedRequest);
Important: Don't attach JWT to every URL blindly
In a real application, you may want the token attached only to your backend API:
export const jwtInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem('access_token');
const isApiRequest =
req.url.startsWith('https://localhost:7001/api');
if (token && isApiRequest) {
req = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
return next(req);
};
This avoids accidentally sending your JWT to third-party APIs.
Multiple Interceptors
You can register multiple interceptors:
provideHttpClient(
withInterceptors([
jwtInterceptor,
loggingInterceptor,
errorInterceptor
])
)
For example:
Angular Component
↓
ProductService
↓
HttpClient
↓
JWT Interceptor
↓
Logging Interceptor
↓
Error Interceptor
↓
ASP.NET Core Web API
Key Points
- Use an HTTP interceptor to attach JWTs automatically.
- Modern standalone Angular can use
HttpInterceptorFn. - Register it with
withInterceptors(). - Read the access token from your authentication/token service or storage.
- Send it using the standard
Authorization: Bearer <token>header. - Use
req.clone()because Angular HTTP requests are immutable. - Prefer restricting token attachment to your own trusted API URLs.
- This centralizes authentication logic instead of duplicating headers in every service.
Interview Answer
Q: How would you automatically attach a JWT to every Angular HTTP request?
Use an Angular HTTP interceptor. The interceptor retrieves the JWT, clones the outgoing request, adds Authorization: Bearer <token>, and passes the cloned request to the next handler.
export const jwtInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem('access_token');
if (token) {
req = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
return next(req);
};
Register it globally:
provideHttpClient(
withInterceptors([jwtInterceptor])
);
After that, every applicable HttpClient request automatically carries the JWT.