Valtuutus.Core 0.8.0-beta

This is a prerelease version of Valtuutus.Core.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Valtuutus.Core --version 0.8.0-beta
                    
NuGet\Install-Package Valtuutus.Core -Version 0.8.0-beta
                    
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="Valtuutus.Core" Version="0.8.0-beta" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Valtuutus.Core" Version="0.8.0-beta" />
                    
Directory.Packages.props
<PackageReference Include="Valtuutus.Core" />
                    
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 Valtuutus.Core --version 0.8.0-beta
                    
#r "nuget: Valtuutus.Core, 0.8.0-beta"
                    
#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 Valtuutus.Core@0.8.0-beta
                    
#: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=Valtuutus.Core&version=0.8.0-beta&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Valtuutus.Core&version=0.8.0-beta&prerelease
                    
Install as a Cake Tool

Valtuutus

A Google Zanzibar inspired authorization library in .NET

The implementation is inspired on permify and other ReBac open source projects.

NuGet Version Coverage Technical Debt Code Smells Reliability Rating Vulnerabilities Bugs Security Rating Maintainability Rating

<a href="https://bencher.dev/perf/valtuutus?key=true&reports_per_page=4&branches_per_page=8&testbeds_per_page=8&benchmarks_per_page=8&plots_per_page=8&reports_page=1&branches_page=1&testbeds_page=1&benchmarks_page=1&plots_page=1&report=f7c35e30-f513-402c-af44-56d8c876fff3&branches=9e4cbdcf-9fee-4cd3-ada1-62aefe433145&heads=5bdd1841-0a0f-4532-84b7-87ef3d065302&testbeds=072da3db-e609-4676-99a6-5b9262df6086&benchmarks=22f44ad6-7979-4757-aa00-3286de603788%2Cd0d39808-ab7a-42f9-95fb-9193853640f3%2Cd3f76a50-964b-4526-9c33-89a38c18f474%2Cb0c2d4d2-2cae-4dfd-89d2-35b49a00b23e&measures=b549a9dd-6ff0-4525-b90a-c9e3af815580&start_time=1714521600000&lower_boundary=false&upper_boundary=false&clear=true&lower_value=false&upper_value=false&x_axis=date_time&end_time=1796083200000&utm_medium=share&utm_source=bencher&utm_content=img&utm_campaign=perf%2Bimg&utm_term=valtuutus"><img src="https://api.bencher.dev/v0/projects/valtuutus/perf/img?branches=9e4cbdcf-9fee-4cd3-ada1-62aefe433145&heads=5bdd1841-0a0f-4532-84b7-87ef3d065302&testbeds=072da3db-e609-4676-99a6-5b9262df6086&benchmarks=22f44ad6-7979-4757-aa00-3286de603788%2Cd0d39808-ab7a-42f9-95fb-9193853640f3%2Cd3f76a50-964b-4526-9c33-89a38c18f474%2Cb0c2d4d2-2cae-4dfd-89d2-35b49a00b23e&measures=b549a9dd-6ff0-4525-b90a-c9e3af815580&start_time=1714521600000&end_time=1797083200000" title="valtuutus" alt="valtuutus - Bencher" /></a>

Functionality

The library is designed to be simple and easy to use. Each subset of functionality is divided in engines. The engines are:

  • ICheckEngine: The engine that handles the answering of two questions:
    • Can entity U perform action Y in resource Z? For that, use the Check function.
    • What permissions entity U have in resource Z? For that, use the SubjectPermission function.
  • ILookupSubjectEngine: The engine that can answer: Which subjects of type T have permission Y on entity:X? For that, use the Lookup function.
  • ILookupEntityEngine: The engine that can answer: Which resources of type T can entity:X have permission Y? For that, use the LookupEntity function. Supports scoped queries and cursor pagination — see below.
  • IDataWriterProvider: This is the provider that can write your relational or attribute data.
  • IDbDataWriterProvider: Works similarly to IDataWriterProvider, with the addition of accepting a connection and transaction as parameters.
  • Read here about how the relational data is stored.
  • Read here for engine usage examples (Check, SubjectPermission, LookupSubject, LookupEntity).

LookupEntity — scoped queries and pagination

LookupEntity returns a LookupEntityPage:

LookupEntityPage page = await lookupEntityEngine.LookupEntity(
    new LookupEntityRequest("task", "view", "user", "alice"),
    cancellationToken);

// page.EntityIds — IReadOnlyList<string>
// page.ContinuationToken — null if no more pages

Scope — constrain results to a parent entity

Use EntityScope when you need to answer a scoped question like "which tasks in project X can this user view?" — the same query you'd back a GET /projects/{projectId}/tasks endpoint with.

Without scope, LookupEntity returns all tasks the user can view across the entire system. With scope, results are limited to tasks that have the specified relation to the given parent entity — so only tasks belonging to project-1 are considered.

var page = await lookupEntityEngine.LookupEntity(
    new LookupEntityRequest("task", "view", "user", "alice")
    {
        Scope = new EntityScope(
            Relation: "parent",      // the relation on "task" that points to its parent
            SubjectType: "project",  // the parent entity type
            SubjectId: "project-1"   // the specific parent to scope to
        )
    },
    cancellationToken);

Pagination

string? token = null;
do
{
    var page = await lookupEntityEngine.LookupEntity(
        new LookupEntityRequest("task", "view", "user", "alice")
        {
            Scope = new EntityScope("parent", "project", "project-1"),
            PageSize = 50,
            ContinuationToken = token
        },
        cancellationToken);

    Process(page.EntityIds);
    token = page.ContinuationToken;
} while (token is not null);

Documentation

Guide Description
Getting Started End-to-end quickstart — install, configure, write data, check permissions
Modeling Authorization Schema DSL walkthrough with the GitHub example
Schema Reference Complete reference for every keyword, operator, and type in the DSL
Authorization Patterns Ready-made patterns: RBAC, hierarchical RBAC, ABAC, multi-tenancy
Using the Engines Code examples for Check, SubjectPermission, LookupSubject, LookupEntity, depth
Storing Data Writing, deleting, snap tokens, source generator
Testing Unit-testing your authorization model with the InMemory provider
Caching Reducing database load with FusionCache
Telemetry OpenTelemetry activity sources, emitted spans, and what to monitor

Usage

Install the package from NuGet:

If using Postgres:

dotnet add package Valtuutus.Data.Postgres

If using SqlServer:

dotnet add package Valtuutus.Data.SqlServer

If you prefer using an InMemory provider:

dotnet add package Valtuutus.Data.InMemory

Adding to DI:

builder.Services.AddValtuutusCore(c =>
        ... 

See examples of how to define your schema here.

If using Postgres:

builder.Services
    .AddPostgres(_ => () => new NpgsqlConnection(builder.Configuration.GetConnectionString("PostgresDb")!));

If using SqlServer:

builder.Services
    .AddSqlServer(_ => () => new SqlConnection(builder.Configuration.GetConnectionString("SqlServerDb")!));

If using InMemory:

builder.Services
    .AddInMemory();

Database migrations

If you are using a DB provider to store your data, please look at the scripts that create the tables that Valtuutus require to function.

Schema and table name customization

Both relational providers accept an optional options object to customise the database schema and table names. Pass it as the second argument to AddPostgres or AddSqlServer:

// Postgres — defaults: schema="public", tables="transactions", "relation_tuples", "attributes"
builder.Services.AddValtuutusCore(/* schema */)
    .AddPostgres(
        _ => () => new NpgsqlConnection(connectionString),
        new ValtuutusPostgresOptions(
            schema:                 "authz",
            transactionsTableName:  "transactions",
            relationsTableName:     "relation_tuples",
            attributesTableName:    "attributes"));

// SQL Server — defaults: schema="dbo", same table names
builder.Services.AddValtuutusCore(/* schema */)
    .AddSqlServer(
        _ => () => new SqlConnection(connectionString),
        new ValtuutusSqlServerOptions(
            schema:                 "authz",
            transactionsTableName:  "transactions",
            relationsTableName:     "relation_tuples",
            attributesTableName:    "attributes"));

Make sure the migration script targets the same schema and table names you configure here.

ValtuutusPostgresOptions also exposes two Npgsql-specific properties for automatic prepared statements:

Property Default Meaning
MaxAutoPrepare 64 Maximum number of statements Npgsql will auto-prepare
AutoPrepareMinUsages 2 Minimum executions before a statement is prepared

These map directly to Npgsql's prepared statement feature and can improve performance for repeated queries under load.

Using query concurrent limiting

It is expected that you don't want to allow Valtuutus to expand queries while it has resources. The default limit is 5 concurrent queries for the same request. To change that, you can use the AddConcurrentQueryLimit method, for example:

builder.Services
    .AddPostgres(_ => () => new NpgsqlConnection(builder.Configuration.GetConnectionString("PostgresDb")!)) // Replace this with any provider you want
    .AddConcurrentQueryLimit(10);

Change your data provider according to your database.

Caching

Valtuutus supports caching the calls to the engines through the Valtuutus.Data.Caching package. To use it, install like:

dotnet add package Valtuutus.Data.Caching

In your DI setup, add the caching component:

builder.Services
    .AddPostgres(_ => () => new NpgsqlConnection(builder.Configuration.GetConnectionString("PostgresDb")!)) // Replace this with any provider you want
    .AddCaching(); // <-- This line

This packages requires that you set up the amazing FusionCache library. Click here for more information.

Telemetry

The library uses OpenTelemetry to provide telemetry data. To enable it, just add a source with the name "Valtuutus":

builder.Services
    .AddOpenTelemetry()
    .WithTracing(telemetry =>
    {
        telemetry
            .AddSource("Valtuutus")
            ...
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 Valtuutus.Core:

Package Downloads
Valtuutus.Data

Valtuutus data access abstractions; Valtuutus provides a developer-focused, modern library for creating ReBAC without complexity.

Valtuutus.Data.Caching

Valtuutus relational caching abstractions; Valtuutus provides a developer-focused, modern library for creating ReBAC without complexity.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.9.0-beta 124 4/20/2026
0.8.2-beta 65 4/17/2026
0.8.1-beta 60 4/17/2026
0.8.0-beta 73 4/13/2026
0.7.3.1-beta 1,137 4/3/2025
0.7.3-beta 201 3/20/2025
0.7.2-beta 131 12/30/2024
0.7.1-beta 135 12/30/2024
0.7.0-beta 122 11/19/2024
0.6.0-beta 136 10/9/2024
0.5.0-beta 144 8/21/2024
0.4.0-alpha 109 7/26/2024
0.3.0-alpha 138 4/4/2024
0.2.0-alpha 142 3/27/2024
0.1.0-alpha 135 3/25/2024

Version 0.8.0-beta:
     BREAKING: Dropped netstandard2.0 — targets are net8.0, net9.0, net10.0
     BREAKING: LookupEntity now returns LookupEntityPage instead of HashSet<string>
     BREAKING: IDataReaderProvider methods gain a required EntityScope? scope parameter
     BREAKING: SnapToken is now required (non-nullable) in data-layer filter types
     NEW: net10.0 target framework support
     NEW: LookupEntity parent-scoped queries via EntityScope
     NEW: Cursor pagination for LookupEntity via PageSize + ContinuationToken
     PERF: ~93% allocation reduction in LookupEntity engine
     PERF: CheckEngine memoization, reachability pruning, and batched dispatch
     PERF: Two-hop and TTU EXISTS JOIN eliminates extra DB round-trips
     PERF: Native Npgsql hot-path readers for relation queries