// Role-based
[Authorize(Roles = "Admin")]
public IActionResult DeleteUser(int id) { ... }
// Claims-based (via policy)
builder.Services.AddAuthorization(options => {
options.AddPolicy("PremiumOnly", policy => policy.RequireClaim("subscription", "premium"));
});
Topics
36
API Documentation with Swagger/OpenAPI
API Versioning
Authentication
Authorization
Background Tasks & Hosted Services
Blazor Integration with ASP.NET Core
Caching
Configuration & Options Pattern
Content Negotiation & Output Formatters
Controllers vs Minimal APIs
CORS (Cross-Origin Resource Sharing)
Dependency Injection
Endpoint Metadata, Route Constraints & Templates
Error Handling
File Uploads & Streaming Large Files
Filters
gRPC Services
Health Checks
Hosting Models: Kestrel, IIS & Reverse Proxies
HTTPS, Certificates & Transport Security
Localization & Globalization
Logging
Model Binding & Validation
MVC Views, Razor Syntax & Tag Helpers
Output Caching & Response Caching
Rate Limiting
Razor Pages
Request Pipeline & Middleware
Response Compression & Caching Headers
Routing
Security Headers, Antiforgery & CSRF Protection
Sessions, Cookies & TempData
SignalR & Real-Time Communication
Static Files, wwwroot & Content Delivery
Testing ASP.NET Core Applications
WebSockets
Authorization
15 questions found
Role-based authorization ([Authorize(Roles = "Admin")]) checks whether the user's ClaimsPrincipal has a role claim matching one of the specified roles -- a simple, coarse-grained check. Claims-based authorization checks for the presence (and optionally the value) of any specific claim type, offering finer-grained control since claims can represent arbitrary attributes beyond just roles (like a subscription tier, department, or permission level).
Real-world example
An e-commerce platform uses role-based authorization for admin functions (Admin, Support roles) but claims-based policies for feature access (checking a 'subscription' claim's value) since subscription tiers aren't naturally modeled as roles.
Authentication;Configuration & Options Pattern
How do you define and apply policy-based authorization for requirements more complex than a simple role or claim check?
IntermediateAddAuthorization registers named policies built from one or more IAuthorizationRequirement objects (or simple RequireClaim/RequireRole/RequireAssertion builder calls for straightforward cases), applied to endpoints via [Authorize(Policy = "PolicyName")] -- letting you express arbitrarily complex authorization logic (combinations of claims, custom business rules) as a reusable, named, centrally-defined policy rather than scattering ad-hoc checks throughout controller code.
builder.Services.AddAuthorization(options => {
options.AddPolicy("MinimumAge", policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(c => c.Type == "age" && int.Parse(c.Value) >= 18)));
});
[Authorize(Policy = "MinimumAge")]
public IActionResult ViewRestrictedContent() { ... }
Real-world example
An age-restricted content endpoint uses a custom MinimumAge policy evaluating a claim's numeric value, expressing logic that a simple role or single-claim check couldn't represent as cleanly.
Authentication;RESTful Web APIs & Controllers
How do you implement resource-based authorization, where the authorization decision depends on the specific object being accessed, not just the user's general permissions?
AdvancedResource-based authorization uses IAuthorizationService.AuthorizeAsync(user, resource, requirement) directly within your action/endpoint (rather than a declarative attribute, since the resource instance isn't known until the object is loaded), combined with a custom IAuthorizationHandler<TRequirement, TResource> that inspects both the user and the specific resource (e.g., checking if the user is the resource's owner) to make the decision.
public class OwnerAuthorizationHandler : AuthorizationHandler<OwnerRequirement, Document> {
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, OwnerRequirement requirement, Document resource) {
if (resource.OwnerId == context.User.FindFirst("sub")?.Value)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
// Usage in an endpoint:
var document = await _repository.GetAsync(id);
var result = await _authorizationService.AuthorizeAsync(User, document, "DocumentOwner");
if (!result.Succeeded) return Forbid();
Real-world example
A document management system ensures users can only edit documents they own by checking resource-based authorization against the actual loaded Document entity's OwnerId, something a declarative [Authorize] attribute alone couldn't express since it has no access to the specific resource instance.
Entity Framework Core & Data Access;Filters
What is the difference between AuthorizeAttribute's behavior returning 401 versus 403, and what determines which one a client receives?
IntermediateA 401 Unauthorized response means the request lacks valid authentication credentials entirely (or they failed to validate) -- the user isn't recognized at all. A 403 Forbidden means the user IS successfully authenticated but lacks sufficient permissions for the specific requested action -- ASP.NET Core's authorization middleware automatically returns the correct one based on whether HttpContext.User.Identity.IsAuthenticated is true or false when an authorization check fails.
// Unauthenticated request to a protected endpoint -> 401
// GET /api/admin/users (no Authorization header at all)
// Authenticated but insufficiently privileged request -> 403
// GET /api/admin/users
// Authorization: Bearer <valid token for a non-admin user>
Real-world example
A frontend application distinguishes between a 401 (redirect to login page, since the session may have expired) and a 403 (show a permanent 'access denied' message, since re-authenticating wouldn't help) based on this status code difference.
Authentication;Error Handling
How would you implement a custom IAuthorizationRequirement and IAuthorizationHandler for a business rule like 'only during business hours'?
AdvancedDefine a class implementing IAuthorizationRequirement (often just a marker with no logic itself), then an AuthorizationHandler<TRequirement> subclass implementing HandleRequirementAsync that evaluates the actual business rule (checking DateTime.Now against configured business hours) and calls context.Succeed(requirement) if satisfied -- registered via services.AddScoped<IAuthorizationHandler, BusinessHoursHandler>() and referenced in a policy.
public class BusinessHoursRequirement : IAuthorizationRequirement { }
public class BusinessHoursHandler : AuthorizationHandler<BusinessHoursRequirement> {
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BusinessHoursRequirement requirement) {
var now = DateTime.Now.TimeOfDay;
if (now >= TimeSpan.FromHours(9) && now <= TimeSpan.FromHours(17))
context.Succeed(requirement);
return Task.CompletedTask;
}
}
builder.Services.AddAuthorization(o => o.AddPolicy("BusinessHoursOnly", p => p.Requirements.Add(new BusinessHoursRequirement())));
Real-world example
A high-risk financial transaction endpoint restricts execution to business hours using a custom requirement/handler pair, ensuring transfers above a threshold can only be initiated when support staff are available to respond to issues.
Configuration & Options Pattern;Filters
How do you apply a global authorization policy requiring authentication by default for every endpoint, with explicit opt-out for public ones?
IntermediateSetting options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build() makes authentication mandatory for every endpoint that doesn't have explicit [Authorize] or [AllowAnonymous] metadata, flipping the default from 'public unless marked otherwise' to 'protected unless explicitly marked public' -- a much safer default posture that prevents accidentally leaving a new endpoint unintentionally unauthenticated.
builder.Services.AddAuthorization(options => {
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
[AllowAnonymous] // must explicitly opt out for public endpoints
[HttpGet("health")]
public IActionResult Health() => Ok();
Real-world example
A security audit recommends switching from the default 'opt-in to protection' model to a fallback policy requiring authentication everywhere by default, after discovering a newly added endpoint had been accidentally left completely unprotected for weeks.
Health Checks;ASP.NET Core Middleware & Request Pipeline
How does the AuthorizationMiddlewareResultHandler let you customize the response returned when authorization fails, beyond the default 401/403?
AdvancedImplementing a custom IAuthorizationMiddlewareResultHandler and registering it lets you intercept authorization failures to return a custom response shape (like a ProblemDetails-formatted JSON error explaining exactly which policy failed) instead of the framework's bare default response, useful for APIs wanting consistent, informative error responses across every kind of failure including authorization.
public class CustomAuthResultHandler : IAuthorizationMiddlewareResultHandler {
private readonly AuthorizationMiddlewareResultHandler _default = new();
public async Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult) {
if (!authorizeResult.Succeeded) {
context.Response.StatusCode = 403;
await context.Response.WriteAsJsonAsync(new { title = "Access denied", policy = policy.AuthenticationSchemes });
return;
}
await _default.HandleAsync(next, context, policy, authorizeResult);
}
}
builder.Services.AddSingleton<IAuthorizationMiddlewareResultHandler, CustomAuthResultHandler>();
Real-world example
An API standardizing all error responses (including authorization failures) on the ProblemDetails format registers a custom result handler so a failed policy check produces the same consistent JSON error shape as any other error type in the application.
Global Exception Handling & Middleware;RESTful Web APIs & Controllers
How do you restrict access to a minimal API endpoint or endpoint group using authorization, given minimal APIs don't use controller attributes?
IntermediateMinimal API endpoints use the fluent .RequireAuthorization() extension method (optionally passing a policy name), applicable to individual endpoints or entire route groups via MapGroup, mirroring the declarative [Authorize] attribute's behavior but in the minimal API's method-chaining style.
app.MapGet("/admin/users", () => GetUsers())
.RequireAuthorization("AdminOnly");
// Applying to an entire group at once
var adminGroup = app.MapGroup("/admin").RequireAuthorization("AdminOnly");
adminGroup.MapGet("/users", () => GetUsers());
adminGroup.MapDelete("/users/{id}", (int id) => DeleteUser(id));
Real-world example
An admin-only minimal API route group applies RequireAuthorization once at the group level, automatically protecting every endpoint mapped within that group without repeating the authorization call on each individual route.
Controllers vs Minimal APIs;Endpoint Metadata
Route Constraints & Templates
How would you implement hierarchical or nested permission checks, like an organization admin having access to all of their organization's resources?
AdvancedA common approach models permissions hierarchically in your data (an OrganizationId claim plus a resource's own OrganizationId field) and implements a resource-based authorization handler that checks whether the user's organization matches (or, for a super-admin role, bypasses the check entirely) -- combining role-based (super-admin bypass) and resource-based (organization membership match) checks within a single handler for a complete hierarchical permission model.
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ResourceAccessRequirement requirement, Project resource) {
if (context.User.IsInRole("SuperAdmin")) { context.Succeed(requirement); return Task.CompletedTask; }
var userOrgId = context.User.FindFirst("org_id")?.Value;
if (userOrgId == resource.OrganizationId.ToString() && context.User.IsInRole("OrgAdmin"))
context.Succeed(requirement);
return Task.CompletedTask;
}
Real-world example
A multi-tenant project management SaaS lets organization admins manage every project within their own organization while a platform-level SuperAdmin role bypasses organizational boundaries entirely for support purposes, both expressed in one authorization handler.
Multiple Inheritance & MRO;Entity Framework Core & Data Access
What is the purpose of the [AllowAnonymous] attribute, and how does it interact with a controller-level [Authorize] attribute?
Intermediate[AllowAnonymous] applied to a specific action overrides an [Authorize] attribute applied at the controller level, letting most of a controller's actions require authentication while specifically exempting individual actions (like a public health check or a login endpoint that logically lives in an otherwise-protected AccountController) -- action-level attributes always take precedence over controller-level ones for this purpose.
[Authorize]
public class AccountController : ControllerBase {
[AllowAnonymous]
[HttpPost("login")]
public IActionResult Login(LoginDto dto) { ... } // publicly accessible despite controller-level [Authorize]
[HttpGet("profile")]
public IActionResult Profile() { ... } // requires authentication (inherits controller-level attribute)
}
Real-world example
An AccountController marked with a blanket [Authorize] attribute still allows anonymous access specifically to its Login and Register actions via [AllowAnonymous], since requiring authentication to log in would be a contradiction.
ASP.NET Core Middleware & Request Pipeline;Controllers vs Minimal APIs
Showing 1–10 of 15