ClaimsPolicyBuilder 1.0.0
dotnet add package ClaimsPolicyBuilder --version 1.0.0
NuGet\Install-Package ClaimsPolicyBuilder -Version 1.0.0
<PackageReference Include="ClaimsPolicyBuilder" Version="1.0.0" />
<PackageVersion Include="ClaimsPolicyBuilder" Version="1.0.0" />
<PackageReference Include="ClaimsPolicyBuilder" />
paket add ClaimsPolicyBuilder --version 1.0.0
#r "nuget: ClaimsPolicyBuilder, 1.0.0"
#:package ClaimsPolicyBuilder@1.0.0
#addin nuget:?package=ClaimsPolicyBuilder&version=1.0.0
#tool nuget:?package=ClaimsPolicyBuilder&version=1.0.0
ClaimsPolicyBuilder
A fluent DSL for building ASP.NET Core claims-based authorization policies with compile-time safety.
Problem
Authorization in ASP.NET Core is powerful but ergonomically poor. AuthorizationPolicyBuilder requires 5–10 lines of repetitive policy.Require* calls per policy, uses magic strings for policy names, and offers no composition story.
Solution
ClaimsPolicyBuilder provides:
- A fluent DSL that expresses policies in 1–2 readable lines
- Compile-time policy name constants via a Roslyn source generator — typos become build errors, not runtime 403s
- Policy composition with
Extends,And, andOr - Zero runtime cost — produces standard
AuthorizationPolicyinstances
Installation
dotnet add package ClaimsPolicyBuilder
Quick Start
services.AddClaimsPolicies(policies =>
{
policies.Add("CanEditInvoices")
.RequireAuthenticated()
.RequireScope("invoices:write")
.RequireAnyRole("Accountant", "Admin")
.RequireClaim("tenant", "acme");
policies.Add("CanViewReports")
.Extends("CanEditInvoices")
.RequireClaim("feature", "reports");
policies.Add("AdminOnly")
.RequireRole("Admin")
.Or(p => p.RequireClaim("override", "true"));
});
Using Generated Policy Name Constants
The source generator emits a Policies class with const string fields:
// Auto-generated at compile time
[Authorize(Policy = Policies.CanEditInvoices)]
public IResult EditInvoice() { ... }
[Authorize(Policy = Policies.AdminOnly)]
public IResult AdminAction() { ... }
Configure the Generated Namespace
Use an assembly attribute:
[assembly: ClaimsPolicyNamespace("MyApp.Auth")]
Or an MSBuild property in your .csproj:
<PropertyGroup>
<ClaimsPolicyBuilder_Namespace>MyApp.Auth</ClaimsPolicyBuilder_Namespace>
</PropertyGroup>
Defaults to <RootNamespace>.Authorization.
API Reference
Policy Registration
| Method | Description |
|---|---|
services.AddClaimsPolicies(Action<IPolicyRegistration>) |
Entry point for registering policies |
policies.Add(string name) |
Creates a new named policy and returns a fluent builder |
Policy Builder
| Method | Description |
|---|---|
.RequireAuthenticated() |
Requires an authenticated user |
.RequireRole(string) |
Requires a single role |
.RequireAnyRole(params string[]) |
Requires any one of the specified roles |
.RequireAllRoles(params string[]) |
Requires all of the specified roles |
.RequireClaim(string type, params string[]) |
Requires a claim with optional allowed values |
.RequireClaimMatching(string type, Func<string, bool>) |
Requires a claim matching a predicate |
.RequireScope(params string[]) |
Requires OAuth2-style scope values (space-separated) |
.RequireAssertion(Func<AuthorizationHandlerContext, bool>) |
Custom assertion escape hatch |
.Extends(string policyName) |
Inherits all requirements from another policy (logical AND) |
.And(Action<IPolicyBuilder>) |
Adds additional requirements (logical AND) |
.Or(Action<IPolicyBuilder>) |
Adds alternative requirements (logical OR) |
Source Generator Diagnostics
| ID | Severity | Description |
|---|---|---|
| CPB001 | Error | Duplicate policy name detected |
| CPB002 | Warning | Policy name is not a valid C# identifier |
Examples
1. Simple Role-Based Policy
services.AddClaimsPolicies(policies =>
{
policies.Add("AdminOnly").RequireRole("Admin");
});
2. Multi-Tenant Policy
services.AddClaimsPolicies(policies =>
{
policies.Add("TenantAccess")
.RequireAuthenticated()
.RequireClaim("tenant", "acme");
});
3. Composed Policies
services.AddClaimsPolicies(policies =>
{
policies.Add("BaseTenant")
.RequireAuthenticated()
.RequireClaim("tenant", "acme");
policies.Add("TenantAdmin")
.Extends("BaseTenant")
.RequireRole("Admin");
});
4. OR Composition
services.AddClaimsPolicies(policies =>
{
policies.Add("CanAccess")
.RequireRole("Admin")
.Or(p => p.RequireClaim("bypass", "true"));
});
5. Scope-Based API Policy
services.AddClaimsPolicies(policies =>
{
policies.Add("ReadWrite")
.RequireAuthenticated()
.RequireScope("api:read", "api:write");
});
Sample App
A runnable ASP.NET Core sample lives in samples/ClaimsPolicyBuilder.Sample. It wires up every policy above and protects minimal-API endpoints with the generated Policies.* constants. A header-driven test auth handler lets you flip a request between allowed and denied without an identity provider:
dotnet run --project samples/ClaimsPolicyBuilder.Sample
# 200 — all requirements met
curl -i http://localhost:5080/invoices/edit \
-H "X-User: alice" -H "X-Roles: Accountant" \
-H "X-Scope: invoices:write" -H "X-Claims: tenant=acme"
# 403 — drop the scope and the same request is forbidden
curl -i http://localhost:5080/invoices/edit \
-H "X-User: alice" -H "X-Roles: Accountant" -H "X-Claims: tenant=acme"
See the sample README and sample.http for the full success/denied matrix of every policy.
Design Decisions
Extendssemantics: Extending means logical AND of all requirements from the parent policy. Override semantics were considered but rejected as surprising in auth contexts.Orimplementation: ASP.NET Core's policy model is AND-only by default.Oris implemented as a singleRequireAssertionwrapping both sub-policies. This loses requirement-level introspection but provides correct OR evaluation.- No replacement: The library produces standard
AuthorizationPolicyinstances. It integrates with existing[Authorize], minimal API.RequireAuthorization(), and Blazor<AuthorizeView>.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 137 | 5/30/2026 |