ZeroAlloc.Authorization 2.0.0

dotnet add package ZeroAlloc.Authorization --version 2.0.0
                    
NuGet\Install-Package ZeroAlloc.Authorization -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ZeroAlloc.Authorization" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ZeroAlloc.Authorization" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ZeroAlloc.Authorization" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ZeroAlloc.Authorization --version 2.0.0
                    
#r "nuget: ZeroAlloc.Authorization, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ZeroAlloc.Authorization@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ZeroAlloc.Authorization&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ZeroAlloc.Authorization&version=2.0.0
                    
Install as a Cake Tool

ZeroAlloc.Authorization

NuGet Build License: MIT AOT GitHub Sponsors

Authorization primitives for .NET — ISecurityContext, IAuthorizationPolicy, [Policy], [RequirePolicy], AnonymousSecurityContext, and an AuthorizerFor<TRequest> dispatcher emitted by the bundled source generator.

Used by:

  • AI.Sentinel — tool-call authorization for IChatClient-based agents
  • ZeroAlloc.Mediator.Authorization v5 — request-handler authorization

Install

dotnet add package ZeroAlloc.Authorization

Targets net8.0, net9.0, net10.0. The package bundles a Roslyn source generator — no separate *.Generator install.

The contract

public interface ISecurityContext
{
    string Id { get; }
    IReadOnlySet<string> Roles { get; }
    IReadOnlyDictionary<string, string> Claims { get; }
}

public interface IAuthorizationPolicy
{
    ValueTask<UnitResult<AuthorizationFailure>> EvaluateAsync(
        ISecurityContext ctx, CancellationToken ct = default);
}

Writing a policy

[Policy("AdminOnly")]
public sealed class AdminOnlyPolicy : IAuthorizationPolicy
{
    public ValueTask<UnitResult<AuthorizationFailure>> EvaluateAsync(
        ISecurityContext ctx, CancellationToken ct = default)
        => new(ctx.Roles.Contains("Admin")
            ? UnitResult<AuthorizationFailure>.Success()
            : new AuthorizationFailure(AuthorizationFailure.DefaultDenyCode, "Admin role required"));
}

Bind it on a request type — [RequirePolicy] is class/struct-level only, and stacks:

[RequirePolicy("AdminOnly")]
public sealed record DeleteUserCommand(string UserId);

[RequirePolicy("ActiveTenant")]
[RequirePolicy("AdminOnly")]
public sealed record PurgeTenantCommand(string TenantId);

Host wiring

The bundled generator emits one AuthorizerFor<TRequest> subclass per [RequirePolicy]-decorated type plus an AddZeroAllocAuthorization() extension on IServiceCollection. Hosts call the extension at startup and resolve AuthorizerFor<T> per request:

using ZeroAlloc.Authorization.Generated;

builder.Services.AddZeroAllocAuthorization();
var authorizer = sp.GetService<AuthorizerFor<DeleteUserCommand>>();
if (authorizer is not null)
{
    var result = await authorizer.EvaluateAsync(securityContext, ct);
    if (result.IsFailure)
        return Forbid(result.Error); // host maps Code / Reason to its outcome shape
}

Hosts can extend ISecurityContext

Hosts define their own subinterface for richer payloads. AI.Sentinel adds IToolCallSecurityContext : ISecurityContext with ToolName + Args. ZeroAlloc.Mediator.Authorization v5 adds IRequestSecurityContext<TRequest>. Inside the policy body, downcast:

public ValueTask<UnitResult<AuthorizationFailure>> EvaluateAsync(
    ISecurityContext ctx, CancellationToken ct = default)
    => new(ctx is IToolCallSecurityContext tc && tc.ToolName == "delete_database"
        ? new AuthorizationFailure("tool.destructive", "destructive tool blocked")
        : UnitResult<AuthorizationFailure>.Success());

I/O-bound policies

For checks that need to await something (tenant lookup, external claims validation), mark EvaluateAsync as async:

[Policy("ActiveTenant")]
public sealed class ActiveTenantPolicy(ITenantService tenants) : IAuthorizationPolicy
{
    public async ValueTask<UnitResult<AuthorizationFailure>> EvaluateAsync(
        ISecurityContext ctx, CancellationToken ct = default)
    {
        var active = await tenants.IsActiveAsync(ctx.Id, ct).ConfigureAwait(false);
        return active
            ? UnitResult<AuthorizationFailure>.Success()
            : new AuthorizationFailure("tenant.inactive", "tenant is suspended");
    }
}

Generator diagnostics

The bundled generator emits five compile-time diagnostics:

ID Fires when
ZAUTH001 [RequirePolicy("X")] references a policy name with no matching [Policy("X")].
ZAUTH002 Two [Policy("X")] declarations share the same name.
ZAUTH003 [Policy] class doesn't implement IAuthorizationPolicy.
ZAUTH004 [Policy] class is abstract or static.
ZAUTH005 [RequirePolicy] placed on a non-class/non-struct target.

Performance

BenchmarkDotNet (BDN ShortRun, .NET 10 release build, x64) — happy path on a simple role-check policy:

Method Mean Allocated
EvaluateAsync ~99 ns 0 B

Source: benchmarks/ZeroAlloc.Authorization.Benchmarks/PolicyEvaluationBenchmarks.cs.

The contract is enforced as zero-allocation by:

  1. <IsAotCompatible>true</IsAotCompatible> on the main library (build-time IL2026/IL3050 analyzers fire on any reflection regression).
  2. The samples/ZeroAlloc.Authorization.AotSmoke/ console app, exercised on each CI run with PublishAot=true.
  3. The benchmark project above.

License

MIT.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on ZeroAlloc.Authorization:

Package Downloads
AI.Sentinel

Security monitoring middleware for IChatClient — prompt injection, hallucination, and operational anomaly detection with an intervention engine.

ZeroAlloc.Mediator.Authorization

Pipeline behavior that authorizes IRequest<T> (or IAuthorizedRequest<T>) via ZeroAlloc.Authorization before dispatch. Source-generated per-request policy lookup; deny throws AuthorizationDeniedException or returns Result<T, AuthorizationFailure> depending on the request marker.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 0 5/19/2026
1.2.2 248 5/12/2026
1.2.1 94 5/7/2026
1.2.0 97 5/6/2026
1.1.1 630 5/3/2026
1.1.0 964 5/1/2026