14. Authentication & Authorization
- Authentication & Authorization
About this chapter
Secure your API by implementing authentication to verify user identity and authorization to control what authenticated users can access.
- Authentication concepts: Verifying user identity with credentials
- Authorization concepts: Controlling resource access based on permissions
- JWT bearer tokens: Stateless token-based authentication
- Token structure and claims: Understanding JWT composition
- Claims-based identity: Using claims for fine-grained authorization
- Implementing authentication: Configuring authentication schemes in .NET 10
Learning outcomes:
- Distinguish between authentication and authorization
- Understand JWT structure and benefits/drawbacks
- Implement JWT authentication in ASP.NET Core
- Work with claims and ClaimsPrincipal
- Configure authentication middleware
- Protect endpoints with authorization attributes
14.1 Understanding Authentication vs Authorization
┌─────────────────────────────────────────────────────────────┐
│ Authentication (AuthN): "Who are you?" │
│ ├─ Verifies identity │
│ ├─ Credentials: username/password, token, certificate │
│ └─ Result: ClaimsPrincipal with claims about the user │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Authorization (AuthZ): "What can you do?" │
│ ├─ Verifies permissions │
│ ├─ Based on: roles, policies, claims │
│ └─ Result: Allow or deny access to resources │
└─────────────────────────────────────────────────────────────┘
Real-World Analogy:
- Authentication: Showing your ID at airport security
- Authorization: Your ticket determines which gate/lounge you can access
14.2 JWT Bearer Tokens Overview
JWT Structure: header.payload.signature
Header (base64):
{
"alg": "RS256",
"typ": "JWT"
}
Payload (base64):
{
"sub": "auth0|123456",
"name": "John Doe",
"email": "john@example.com",
"iat": 1516239022,
"exp": 1516242622,
"aud": "https://api.example.com",
"iss": "https://your-tenant.auth0.com/"
}
Signature:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
JWT Benefits:
- Stateless (no server-side session storage)
- Self-contained (all info in token)
- Cross-domain (CORS-friendly)
- Scalable (no session sharing needed)
JWT Drawbacks:
- Cannot revoke before expiration (unless using token blacklist)
- Size larger than session IDs
- Exposed data (base64 is encoding, not encryption)
14.3 Claims-Based Identity
// Claims are key-value pairs about the user
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, "auth0|123456"),
new Claim(ClaimTypes.Name, "John Doe"),
new Claim(ClaimTypes.Email, "john@example.com"),
new Claim("subscription_level", "premium"),
new Claim("created_date", "2023-01-15")
};
var identity = new ClaimsIdentity(claims, "Bearer");
var principal = new ClaimsPrincipal(identity);
// Accessing claims in controllers
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var email = User.FindFirst(ClaimTypes.Email)?.Value;
var isPremium = User.HasClaim("subscription_level", "premium");
Common Claim Types:
- ClaimTypes.NameIdentifier - Unique user ID (sub in JWT)
- ClaimTypes.Name - Display name
- ClaimTypes.Email - Email address
- ClaimTypes.Role - User roles
- Custom claims for app-specific data
14.4 CORRECTION: Explicitly Adding UseAuthentication() and UseAuthorization()
// ❌ WRONG (current code has comment saying these aren't needed)
// confirm we don't need to explicitly add Authentication and Authorization
app.MapControllers();
// ✅ CORRECT - Always be explicit!
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("JavascriptClient");
// CRITICAL: Add these explicitly in correct order
app.UseAuthentication(); // First: Authenticate the user
app.UseAuthorization(); // Then: Authorize based on policies
app.MapControllers();
app.Run();
Why Explicit is Better:
- Clarity: Future developers understand the pipeline
- Debugging: Easier to troubleshoot auth issues
- Documentation: Self-documenting code
- Framework Changes: Don’t rely on implicit behavior
- Best Practice: Official Microsoft guidance