Clustron.Keyvus.Oidc
1.1.0
dotnet add package Clustron.Keyvus.Oidc --version 1.1.0
NuGet\Install-Package Clustron.Keyvus.Oidc -Version 1.1.0
<PackageReference Include="Clustron.Keyvus.Oidc" Version="1.1.0" />
<PackageVersion Include="Clustron.Keyvus.Oidc" Version="1.1.0" />
<PackageReference Include="Clustron.Keyvus.Oidc" />
paket add Clustron.Keyvus.Oidc --version 1.1.0
#r "nuget: Clustron.Keyvus.Oidc, 1.1.0"
#:package Clustron.Keyvus.Oidc@1.1.0
#addin nuget:?package=Clustron.Keyvus.Oidc&version=1.1.0
#tool nuget:?package=Clustron.Keyvus.Oidc&version=1.1.0
Keyvus
Host-neutral identity, authentication, and RBAC for .NET services.
Keyvus is an embeddable library (SDK) — not a service, daemon, or app. It has no UI, no CLI, and no process, port, or config file of its own. A host product declares its own permissions and roles; Keyvus authenticates callers and answers one question at every enforcement point: "may this caller do X on Y?" — against a role-based access-control model, with tokens verified offline.
Everything product-specific (which operations exist, where policy lives, which endpoints enforce) sits on the host side of a small, fixed set of seams. Keyvus supplies the machinery; the host supplies the vocabulary. Its first consumer is Clustron DKV (a distributed key/value store), and it is built to be adopted by unrelated products — a queue, a cache, a gateway — each with a completely different vocabulary.
- Version: 0.23.0
- Targets: the core libraries target
netstandard2.0(usable from .NET Framework 4.8 and .NET 8+); the ASP.NET Core adapter and tests targetnet8.0. - License: Apache-2.0.
The model in one paragraph
A Permission is an opaque, host-owned operation id ("product.delete"). A Role is a set of
permissions. A RoleBinding grants a role to a principal at a ResourceScope — a hierarchical,
prefix-matched path (market:store:acme), where a grant at one level implies the levels beneath it.
A caller is authenticated into an AccessPrincipal (subject + roles + claims) from a bearer JWT
that is verified offline against the issuer's JWKS. Authorization is then a pure function:
does any effective (role, scope) binding for this principal include the required permission at the
required scope? — deny by default. Policy is data, cached at each enforcement point with a
change-watch, so a grant or revocation propagates in seconds without a per-request central call.
How a request is authorized
flowchart LR
C["Caller"] -->|"Bearer JWT"| MW["Keyvus middleware<br/>(or host seam)"]
MW -->|"verify offline vs JWKS"| V["Token validator<br/>built-in / OIDC"]
V --> P["AccessPrincipal<br/>subject + roles + claims"]
P --> A{"Authorizer.Check<br/>permission @ scope"}
CAT[["Catalog<br/>permissions + roles"]] --> A
POL[["Policy store<br/>role bindings"]] --> A
A -->|"allow"| OK["handler runs"]
A -->|"deny by default"| NO["403 / Unauthorized"]
A -. "audit allow + deny" .-> AUD[["IAuditSink<br/>(host persists)"]]
The host owns the two data sources on the left of the decision: the catalog (what operations and preset roles exist) and the policy store (who is granted what, where). Keyvus owns the decision.
Packages
| Package | Target | Contents |
|---|---|---|
Clustron.Keyvus.Abstractions |
netstandard2.0 | Core POCOs (AccessPrincipal, Permission, ResourceScope, AccessDecision) and every seam interface. Pure contracts. |
Clustron.Keyvus.Rbac |
netstandard2.0 | RBAC engine, catalog, in-memory policy store, policy admin, first-admin bootstrap, and the one-call AddKeyvus DI. |
Clustron.Keyvus.Tokens |
netstandard2.0 | Built-in JWT issuer/validator (RS256/ES256), JWKS, signing-key rotation, secret stores. |
Clustron.Keyvus.Oidc |
netstandard2.0 | External-IdP token validation and group-to-role mapping (federation). |
Clustron.Keyvus.AspNetCore |
net8.0 | Middleware plus the .RequirePermission("…") endpoint ergonomic for HTTP hosts. |
Clustron.Keyvus.Stores.File |
netstandard2.0 | Durable file-backed IPolicyStore (JSON, atomic writes, change-watch) for single-node hosts. |
Clustron.Keyvus.Stores.EntityFrameworkCore |
net8.0 | Database-backed IPolicyStore (SQL Server / PostgreSQL / SQLite / …) with version-polling change-watch — the reference cluster policy store. |
The smallest useful integration is Abstractions + Rbac; a host adds only what it needs.
Quick start
Declaring your vocabulary and wiring Keyvus is one call; enforcing is one line.
// 1. Declare your vocabulary and wire Clustron.Keyvus.
services.AddKeyvus(cat =>
{
cat.Permission("store.stop", plane: Plane.Control, appliesTo: "store");
cat.Permission("data.write", plane: Plane.Data, appliesTo: "store");
cat.PresetRole("StoreOperator", scopeLevel: "store", "store.stop");
cat.PresetRole("DataWriter", scopeLevel: "store", "data.write");
});
services.AddKeyvusBuiltInIssuer(t => t.Issuer = "keyvus://acme"); // optional: issue your own JWTs
services.AddKeyvusAspNetCore(); // optional: HTTP adapter
// 2a. Enforce over HTTP.
app.UseKeyvus(); // resolves the caller principal from the bearer token
app.MapPost("/stores/{store}/stop", StopStore)
.RequirePermission("store.stop", "acme:store:{store}"); // deny -> 403
// 2b. …or anywhere (e.g. a raw-socket data plane), enforce directly.
var decision = authorizer.Check(principal, "data.write", ResourceScope.Parse($"acme:store:{store}"));
if (!decision.Allowed) return Unauthorized(decision.Reason);
// 3. Manage who can do what — all API, no Keyvus UI.
await policyAdmin.GrantAsync("bob@acme.com", "DataWriter",
ResourceScope.Parse("acme:store:orders"), grantedBy: "alice@acme.com");
Integrate now, enforce later: register .AllowAllForDevelopment() first — byte-for-byte your
current unauthenticated behaviour, with a loud startup warning — then switch to the real engine
through DI alone, with no call-site changes.
Full references: docs/API_REFERENCE.md,
docs/CONFIGURATION.md, and — for shared signing keys and a shared policy
store across nodes — docs/MULTI_NODE_DEPLOYMENT.md.
Sample: Keyvus Market
samples/KeyvusMarket is a complete, runnable ASP.NET Core app —
a multi-store marketplace — that consumes Keyvus as NuGet packages and exercises every feature:
built-in tokens, OIDC federation, both at once, scoped cross-store denial, runtime roles and grants,
audit, the file policy store, first-admin bootstrap, break-glass recovery, and AllowAll dev mode.
./pack-local.sh # pack the Clustron.Keyvus.* packages into ./nuget-local
cd samples/KeyvusMarket
dotnet run --urls http://localhost:5080
Then open http://localhost:5080/swagger and follow the numbered
guides. A typical first run:
- The app logs a single-use bootstrap token on startup (there are no default credentials).
POST /auth/loginwith a seeded user returns a JWT; click Authorize in Swagger and paste it.GET /stores/acme/productssucceeds for aStoreManagergranted onacme…- … and the same call on a store they were not granted returns 403 — scopes in action.
GET /admin/auditshows the allow/deny decisions Keyvus emitted for each check.
Swap behaviour without code changes via Market__AuthMode (BuiltIn | Oidc | Both | AllowAll)
and Market__PolicyStore (InMemory | File).
How it works
- Authentication. Callers present a short-lived JWT — from the built-in issuer or a federated
OIDC provider — as
Authorization: Bearer …. Every token is verified offline against the issuer's JWKS; there is no per-request round-trip to an auth server. Service-to-service callers may use X.509 certificates instead. - Authorization. Deny by default. Access is granted only when some effective
(role, scope)binding for the principal contains the required permission at (or above) the required scope. - Policy is data. Bindings live in an
IPolicyStore(in-memory, file, or EF Core), cached at each enforcement point with a change-watch, so revocations and new grants take effect in seconds. - The host provides the encrypted transport (Keyvus assumes it) and an
IAuditSink(Keyvus emits decisions; the host persists them). Operability is built in: first-admin bootstrap (single-use token, no default credentials) and break-glass recovery (host-initiated, gated on local machine access, audited).
Build and test
Requires the .NET 8 SDK (the core libraries also target netstandard2.0).
dotnet build Clustron.Keyvus.sln -c Release
dotnet test Clustron.Keyvus.sln -c Release # 167 tests across six test projects
./pack-local.sh # pack all Clustron.Keyvus.* packages into ./nuget-local
CI (.github/workflows/ci.yml) builds, tests, and packs on both Windows and Linux on every push
and PR.
Clustron.Keyvus.Stores.Truthand its tests are intentionally excluded fromClustron.Keyvus.slnbecause they reference a sibling repository; build them explicitly if you need the Truth-backed store.
Documentation
- Access-control requirements — the full model and rules
- API reference
- Configuration
- Multi-node deployment
- Sample guides
License
Apache-2.0 — see LICENSE. A security framework earns trust and contributions by being
freely reusable.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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 was computed. 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 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Clustron.Keyvus.Abstractions (>= 1.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
- Microsoft.IdentityModel.JsonWebTokens (>= 8.1.2)
- Microsoft.IdentityModel.Protocols.OpenIdConnect (>= 8.1.2)
- Microsoft.IdentityModel.Tokens (>= 8.1.2)
- System.Text.Json (>= 8.0.6)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.