# Query Authorization Secure your queries with authorization services. ## Interface ```csharp public interface IQueryAuthorizationService { Task CanExecuteAsync( TQuery query, ClaimsPrincipal user, CancellationToken cancellationToken = default); } ``` ## Basic Authorization ### Authenticated Users Only ```csharp public class GetUserAuthorizationService : IQueryAuthorizationService { public Task CanExecuteAsync( GetUserQuery query, ClaimsPrincipal user, CancellationToken cancellationToken) { return Task.FromResult(user.Identity?.IsAuthenticated == true); } } // Registration builder.Services.AddScoped, GetUserAuthorizationService>(); ``` ## Resource-Based Authorization ### Own Data Only ```csharp public class GetUserAuthorizationService : IQueryAuthorizationService { public Task CanExecuteAsync( GetUserQuery query, ClaimsPrincipal user, CancellationToken cancellationToken) { // Admins can view any user if (user.IsInRole("Admin")) return Task.FromResult(true); // Users can only view their own data var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value; return Task.FromResult(query.UserId.ToString() == userId); } } ``` ### Row-Level Security ```csharp public class ListOrdersAuthorizationService : IQueryAuthorizationService { public Task CanExecuteAsync( ListOrdersQuery query, ClaimsPrincipal user, CancellationToken cancellationToken) { // Ensure user can only see their own orders (enforced in query handler) var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(userId)) return Task.FromResult(false); // Authorization passes - handler will filter by userId return Task.FromResult(true); } } // In handler: public async Task> HandleAsync(ListOrdersQuery query, CancellationToken cancellationToken) { var userId = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; var orders = await _context.Orders .Where(o => o.UserId.ToString() == userId) // Filter by user .ToListAsync(cancellationToken); return orders.Select(MapToDto).ToList(); } ``` ## Tenant Isolation ```csharp public class GetCustomerAuthorizationService : IQueryAuthorizationService { public Task CanExecuteAsync( GetCustomerQuery query, ClaimsPrincipal user, CancellationToken cancellationToken) { var tenantId = user.FindFirst("TenantId")?.Value; if (string.IsNullOrEmpty(tenantId)) return Task.FromResult(false); // Authorization passes - handler will filter by tenant return Task.FromResult(true); } } ``` ## Best Practices ### ✅ DO - Check resource ownership - Validate tenant isolation - Use for access control - Log authorization failures - Return boolean (true/false) ### ❌ DON'T - Don't throw exceptions - Don't perform business logic - Don't modify data - Don't bypass framework checks ## HTTP Responses - **401 Unauthorized** - User not authenticated - **403 Forbidden** - User authenticated but not authorized ## See Also - [Command Authorization](../commands/command-authorization.md) - [Best Practices: Security](../../best-practices/security.md) - [Extensibility Points](../../architecture/extensibility-points.md)