1. How Does Angular Send a JWT to ASP.NET Core?
What is it?
After a successful login, Angular receives a JWT from the ASP.NET Core Web API.
For subsequent protected API calls, Angular sends the JWT in the standard HTTP Authorization header using the Bearer scheme:
Authorization: Bearer <JWT_TOKEN>
For example:
GET /api/products
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Normally, an Angular HTTP interceptor automatically attaches the JWT to outgoing API requests.
Full Simple Angular Program
auth.service.ts
This service logs in and stores the returned token.
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { tap } from 'rxjs';
interface LoginResponse {
token: string;
}
@Injectable({
providedIn: 'root'
})
export class AuthService {
private http = inject(HttpClient);
login(username: string, password: string) {
return this.http
.post<LoginResponse>(
'https://localhost:7001/api/auth/login',
{
username,
password
}
)
.pipe(
tap(response => {
localStorage.setItem(
'token',
response.token
);
})
);
}
getToken(): string | null {
return localStorage.getItem('token');
}
logout(): void {
localStorage.removeItem('token');
}
}
auth.interceptor.ts
The interceptor automatically adds the JWT.
import {
HttpInterceptorFn
} from '@angular/common/http';
export const authInterceptor: HttpInterceptorFn =
(req, next) => {
const token =
localStorage.getItem('token');
if (token) {
const authRequest =
req.clone({
setHeaders: {
Authorization:
`Bearer ${token}`
}
});
return next(authRequest);
}
return next(req);
};
app.config.ts
Register the interceptor:
import {
ApplicationConfig
} from '@angular/core';
import {
provideHttpClient,
withInterceptors
} from '@angular/common/http';
import {
authInterceptor
} from './auth.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withInterceptors([
authInterceptor
])
)
]
};
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);
private apiUrl =
'https://localhost:7001/api/products';
getProducts() {
return this.http.get(this.apiUrl);
}
}
Notice that ProductService doesn't manually add the JWT.
We only write:
return this.http.get(this.apiUrl);
The interceptor handles authentication automatically.
How Angular Sends the JWT
Suppose Angular executes:
this.http.get(
'https://localhost:7001/api/products'
);
Step 1 — Request enters interceptor
ProductService
↓
HttpClient
↓
Auth Interceptor
Step 2 — Interceptor gets token
const token =
localStorage.getItem('token');
For example:
eyJhbGciOiJIUzI1NiIs...
Step 3 — Interceptor clones request
Angular HTTP requests are immutable, so we create a modified copy:
const authRequest =
req.clone({
setHeaders: {
Authorization:
`Bearer ${token}`
}
});
Step 4 — Actual request
The browser sends:
GET https://localhost:7001/api/products
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
So the flow is:
Angular Component
↓
ProductService
↓
HttpClient
↓
Auth Interceptor
↓
Get JWT
↓
Add Authorization Header
↓
ASP.NET Core Web API
2. How Does ASP.NET Core Validate a JWT?
What is it?
ASP.NET Core receives the JWT from:
Authorization: Bearer <token>
The JWT Bearer authentication handler extracts and validates the token.
It typically verifies:
Signature
Issuer
Audience
Expiration
If validation succeeds, ASP.NET Core creates an authenticated ClaimsPrincipal and stores it in:
HttpContext.User
Full Simple ASP.NET Core Configuration
appsettings.json
{
"Jwt": {
"Key": "ThisIsMySuperSecretKeyForJwtAuthentication12345",
"Issuer": "MyWebApi",
"Audience": "MyAngularApp"
}
}
For production, the signing secret should be kept in an appropriate secret store rather than committed to configuration files.
Program.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// Get JWT configuration
var jwtKey =
builder.Configuration["Jwt:Key"]!;
var jwtIssuer =
builder.Configuration["Jwt:Issuer"]!;
var jwtAudience =
builder.Configuration["Jwt:Audience"]!;
// Configure authentication
builder.Services
.AddAuthentication(
JwtBearerDefaults.AuthenticationScheme
)
.AddJwtBearer(options =>
{
options.TokenValidationParameters =
new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer =
jwtIssuer,
ValidAudience =
jwtAudience,
IssuerSigningKey =
new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtKey)
)
};
});
// Configure authorization
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseHttpsRedirection();
// Authentication first
app.UseAuthentication();
// Authorization second
app.UseAuthorization();
app.MapControllers();
app.Run();
ProductsController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace JwtDemo.Controllers;
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult GetProducts()
{
var products = new[]
{
new
{
Id = 1,
Name = "Laptop"
},
new
{
Id = 2,
Name = "Mouse"
}
};
return Ok(products);
}
}
How ASP.NET Core Validates the JWT
Angular sends:
GET /api/products
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
ASP.NET Core processes it roughly like this:
HTTP Request
↓
Authorization Header
↓
Bearer Token
↓
JWT Bearer Authentication Handler
↓
Validate Token
↓
Create ClaimsPrincipal
↓
HttpContext.User
↓
Authorization
↓
[Authorize]
↓
Controller
Let's examine the important validations.
1. Validate Signature
Configuration:
ValidateIssuerSigningKey = true
and:
IssuerSigningKey =
new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtKey)
);
This verifies that the token has a valid cryptographic signature from a trusted key.
Conceptually:
JWT received
↓
Validate signature
↓
Trusted signing key?
↓
Yes → Continue
No → Reject
If somebody changes the token payload, such as changing:
Role = User
to:
Role = Admin
without being able to create a valid new signature, validation fails.
2. Validate Issuer
ValidateIssuer = true;
ValidIssuer = "MyWebApi";
Issuer answers:
Who issued this token?
The JWT might contain:
iss = MyWebApi
ASP.NET Core compares it with:
MyWebApi
If they don't match, validation fails.
3. Validate Audience
ValidateAudience = true;
ValidAudience = "MyAngularApp";
Audience answers:
Who is this token intended for?
The token might contain:
aud = MyAngularApp
ASP.NET Core checks it against the configured acceptable audience.
4. Validate Expiration
ValidateLifetime = true;
Suppose the JWT was generated with:
expires:
DateTime.UtcNow.AddMinutes(30)
After the expiration time:
JWT
↓
Check expiration
↓
Expired
↓
Authentication fails
↓
401 Unauthorized
5. ASP.NET Core Creates HttpContext.User
If validation succeeds, ASP.NET Core constructs a ClaimsPrincipal.
For example, the token may contain claims corresponding to:
Name = admin
Role = Admin
ASP.NET Core makes them available through:
HttpContext.User
For example:
var username =
User.Identity?.Name;
You can also inspect claims:
var claims =
User.Claims.ToList();
6. [Authorize] Checks Authentication
The controller has:
[Authorize]
So:
Valid JWT
↓
Authenticated ClaimsPrincipal
↓
[Authorize]
↓
Controller executes
If authentication is missing or invalid:
Missing / Invalid JWT
↓
No authenticated user
↓
[Authorize]
↓
401 Unauthorized
Role-Based Authorization
Suppose your JWT contains:
Role = Admin
You can protect an endpoint:
[Authorize(Roles = "Admin")]
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
return Ok();
}
Now the flow becomes:
Validate JWT
↓
Authenticated?
↓
YES
↓
Check Role = Admin
↓
YES ─────────→ Controller
↓
NO
↓
403 Forbidden
This illustrates the distinction between authentication and authorization.
Complete End-to-End Flow
┌──────────────────────────┐
│ Angular │
│ │
│ ProductService │
└────────────┬─────────────┘
│
▼
HttpClient
│
▼
Auth Interceptor
│
│ Read JWT
│
▼
Authorization:
Bearer <JWT>
│
▼
┌──────────────────────────┐
│ ASP.NET Core Web API │
│ │
│ JWT Bearer Authentication│
└────────────┬─────────────┘
│
├── Signature ✓
│
├── Issuer ✓
│
├── Audience ✓
│
└── Lifetime ✓
│
▼
HttpContext.User
│
▼
Authorization
│
▼
[Authorize]
│
▼
ProductsController
│
▼
200 OK
Important: Who Does What?
| Operation | Angular | ASP.NET Core |
|---|---|---|
| Receive JWT after login | ✓ | |
| Store/manage token on client | ✓ | |
| Attach JWT to request | ✓ | |
| Use Bearer header | ✓ | |
| Read Bearer JWT from request | ✓ | |
| Validate signature | ✓ | |
| Validate issuer | ✓ | |
| Validate audience | ✓ | |
| Validate expiration | ✓ | |
Create HttpContext.User |
✓ | |
Apply [Authorize] |
✓ | |
| Enforce roles/policies | ✓ |
The easiest way to remember this is:
Angular
↓
SEND JWT
ASP.NET Core
↓
VALIDATE JWT
Key Points
- Angular normally sends JWT through the HTTP
Authorizationheader. - The standard format is:
Authorization: Bearer <JWT>
- An Angular HTTP interceptor is commonly used so every API service doesn't have to manually add the token.
- ASP.NET Core's JWT Bearer authentication handler performs server-side token validation.
- Common validation includes signature, issuer, audience, and lifetime.
- After successful authentication, claims are available through
HttpContext.User. [Authorize]protects endpoints.[Authorize(Roles = "Admin")]adds role-based authorization.- Missing/invalid authentication normally produces 401 Unauthorized.
- An authenticated user without the required authorization normally receives 403 Forbidden.
- Angular route guards and UI checks are useful for UX, but the ASP.NET Core API must enforce actual security.
Interview Questions & Answers
1. How does Angular send JWT to ASP.NET Core?
Angular sends the JWT in the HTTP Authorization header using the Bearer scheme:
Authorization: Bearer <token>
An HTTP interceptor is commonly used to attach it automatically.
2. Why do we use an Angular interceptor for JWT?
It centralizes token attachment. Instead of adding the Authorization header in every API service, the interceptor automatically adds it to appropriate outgoing requests.
3. How does ASP.NET Core validate a JWT?
ASP.NET Core's JWT Bearer authentication handler reads the Bearer token and validates its signature, issuer, audience, and lifetime according to TokenValidationParameters.
4. What is AddJwtBearer()?
.AddJwtBearer(...)
configures JWT Bearer authentication in ASP.NET Core, including how incoming access tokens should be validated.
5. What is TokenValidationParameters?
It specifies the token validation rules, for example:
ValidateIssuer = true;
ValidateAudience = true;
ValidateLifetime = true;
ValidateIssuerSigningKey = true;
6. What happens after successful JWT validation?
ASP.NET Core creates an authenticated ClaimsPrincipal and assigns it to:
HttpContext.User
Authorization can then evaluate the user's claims, roles, and policies.
7. What happens when the JWT is expired?
With:
ValidateLifetime = true
an expired token fails authentication, and a protected endpoint normally returns:
401 Unauthorized
8. What is the difference between UseAuthentication() and UseAuthorization()?
app.UseAuthentication();
establishes who the user is from the configured authentication mechanism.
app.UseAuthorization();
determines whether that user is allowed to access the requested resource.
9. Which should come first?
Authentication should precede authorization:
app.UseAuthentication();
app.UseAuthorization();
Conceptually:
Authentication
"Who are you?"
↓
Authorization
"What are you allowed to do?"
Interview Quick Answer
Angular sends the JWT in the
Authorization: Bearer <token>header, usually through an HTTP interceptor. ASP.NET Core's JWT Bearer authentication handler extracts the token, validates its signature, issuer, audience, and expiration, creates the authenticatedClaimsPrincipal, and then authorization rules such as[Authorize], roles, claims, or policies determine whether the request can access the endpoint.