Pragmatic.Authorization
The authorization engine for Pragmatic.Design: permissions, roles, groups, wildcard matching, resource (instance-level) policies, and a permission cache — declarative and observable.
The Problem
Section titled “The Problem”Authorization in most .NET apps starts simple and rots. Permission strings are hardcoded and scattered
across controllers; role-to-permission mapping lives in if-statements; wildcard handling is
hand-rolled and inconsistent; instance-level checks (“can this user act on this invoice?”) are buried
in business logic. Ask “what can the booking-manager role do?” and the answer means reading every
controller.
// Typical: scattered, fragile, invisiblevar permissions = User.Claims.Where(c => c.Type == "permission").Select(c => c.Value).ToHashSet();if (!permissions.Contains("booking.reservation.cancel") && !permissions.Any(p => p == "booking.reservation.*") && !permissions.Contains("*")) return Forbid();The Solution
Section titled “The Solution”Declare what is protected and how; the framework handles resolution, wildcard matching, caching, and enforcement.
[RequirePermission(BookingPermissions.Reservation.Cancel)][RequirePolicy<ReservationCancellationPolicy>]public sealed partial class CancelReservationAction : VoidDomainAction{ // business logic only — no authorization code here}// Roles compose from module definitions, declared once in Program.csapp.UseAuthorization(authz =>{ authz.MapRole<BookingManagerRole>(r => r .IncludeDefinition<BookingOperator>() .IncludeDefinition<CatalogReader>()); authz.AddResourceAuthorizer<InvoiceAuthorizer>(); // instance-level (ABAC) authz.UsePermissionCache(TimeSpan.FromMinutes(5));});What it covers
Section titled “What it covers”- Permissions — wildcard-aware matching (
booking.*,*), generatedPermissionConstantsfromIPermission/IRoledefinitions. - Roles & groups — compose roles from reusable definitions; map groups to roles.
- Resource policies (
ResourcePolicy) — instance-level “can this user act on this object?” checks. - Stores & caching — pluggable role/permission/group stores; cross-request
HybridCache. - Pipeline enforcement —
[RequirePermission]/[RequirePolicy]enforced in the Actions/Endpoints pipeline.
Installation
Section titled “Installation”dotnet add package Pragmatic.Authorizationdotnet add package Pragmatic.SourceGenerator # generates permission constants/registryStatus
Section titled “Status”Roles, groups, wildcard permissions, resource authorizers, and the permission cache are functional within the 0.8 preview. See the roadmap.
| Concepts | Mental model, permission strings, the resolution chain, where authorization runs |
| Getting Started | Protect an action, define permissions, map a role |
| Permission Resolution | The full resolution chain, wildcard matching, caching |
| Roles & Groups | IRole/IRoleDefinition, composition, groups |
| Policies | ResourcePolicy, [RequirePolicy<T>], instance-level (ABAC) checks |
| Stores | Role/permission/group stores, customization, temporal/tenant variants |
| Common Mistakes | The most frequent authorization pitfalls |
| Troubleshooting | Problem/solution guide with diagnostics |
Cross-module integration
Section titled “Cross-module integration”Enforced by Actions and Endpoints;
identity comes from Identity; data-level filters live in
Persistence. Interfaces live in Pragmatic.Abstractions.
Requirements
Section titled “Requirements”- .NET 10.0+
Pragmatic.SourceGeneratoranalyzer
License
Section titled “License”Part of the Pragmatic.Design ecosystem — see Licensing. Pragmatic.Authorization is licensed under the PolyForm Small Business 1.0.0 license (free for small businesses; commercial license above the threshold).