WebSvc.CrudAdmin 1.7.0

dotnet add package WebSvc.CrudAdmin --version 1.7.0
                    
NuGet\Install-Package WebSvc.CrudAdmin -Version 1.7.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="WebSvc.CrudAdmin" Version="1.7.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="WebSvc.CrudAdmin" Version="1.7.0" />
                    
Directory.Packages.props
<PackageReference Include="WebSvc.CrudAdmin" />
                    
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 WebSvc.CrudAdmin --version 1.7.0
                    
#r "nuget: WebSvc.CrudAdmin, 1.7.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 WebSvc.CrudAdmin@1.7.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=WebSvc.CrudAdmin&version=1.7.0
                    
Install as a Cake Addin
#tool nuget:?package=WebSvc.CrudAdmin&version=1.7.0
                    
Install as a Cake Tool

WebSvc.CrudAdmin (v1.6.0)

Unified Admin UI + IAM for multi-tenant Dynamic CRUD API platforms — database registration, API-key/Basic/JWT authentication, role-based permissions, row-level policies, tenant self-service, and machine-to-machine provisioning, all in one package.

⚠ CRITICAL — Program.cs Setup

builder.Services.AddCrudAdmin(o => { o.RequireAuth = true; });

var app = builder.Build();

app.UseRouting();
app.UseSetupWizardGate();      // ✅ blocks everything but /setup until first-run setup is done
app.UseCrudAdminPipeline();    // ✅ CORS → admin auth → audit → CrudAuth → tenant resolver → permissions
app.MapCrudAdmin();            // ✅ REQUIRED — maps /admin/* pages and /api/admin/* endpoints
app.Run();

UseCrudAdminPipeline() is the all-in-one for UseCrudCors/UseCrudAdmin/UseCrudAudit/ UseCrudAuth/UseProvisioning/UseTenantPortal/UseCrudTenantResolver/UseCrudPermissions in the correct order — call the individual Use* extensions yourself only if you need custom ordering. If you comment out app.MapCrudAdmin(), you will get 404 on /admin/login.

First run — no default credential

There is no seeded admin/admin@123 account — a fresh install redirects everything except /setup to a first-run wizard that creates the real first admin account. Existing installs upgraded from before this existed are grandfathered in automatically (setup.completed=true) without being forced through it again.

Storage: SQLite (default) or MySQL

The admin registry (tenants, databases, credentials, roles, audit log, settings — everything under /admin) runs on either engine behind one IAdminDbConnectionFactory/SqlDialect abstraction. SQLite is the zero-config default; set CRUDADMIN_DB_ENGINE=mysql + CRUDADMIN_MYSQL_CONNECTION_STRING=... (env vars, read at startup before the store is created) to run on MySQL from first boot instead. An existing SQLite install can move to MySQL later without a fresh setup, via the Migrate to MySQL wizard at /admin/migrate-mysql (Services/MySqlMigrationService.cs) — copies every table across, then the env vars above switch the running instance over.

Stored database credentials (db_password_encrypted, connection_string) are encrypted at rest via CredentialProtector, using ASP.NET Core's Data Protection API — keys persist under {DataDirectory}/keys, so back up that folder alongside the database file itself.

Tenant self-service portal

A tenant's own API-key holder can sign in at /tenant/login (using an unscoped, non-global drk_-prefixed "login key") to reach /tenant/workspace: manage their own databases and API keys, view their own audit trail, and edit tenant-level settings — always forced to their own tenant_id, no route accepts a caller-supplied one. A Global Admin can force-revoke any tenant's active portal session from /admin/tenantsessions.

Provisioning Keys — machine-to-machine onboarding

For an external system (e.g. a customer dashboard) to create tenants and databases in real time with no human admin session: a Provisioning Key (pvk_-prefixed, managed at /admin/provisioningkeys) authenticates via the X-Provisioning-Key header against /api/provision/tenants, /api/provision/databases, /api/provision/bootstrap, and /api/provision/status (Endpoints/ProvisioningEndpoints.cs). Each key is scoped by an optional tenant_id_prefix and a hard max_databases quota, with mandatory expiry, idempotent tenant creation, and full audit logging — a key can only ever create/see what it created.

Cross-app auto-login handoff

CrudAdmin can hand an already-authenticated session off to an independent add-on package (WebSvc.RateLimitAdmin, WebSvc.SqliteAdmin) without the browser ever seeing a password, via CrossAppHandoffService (Services/CrossAppHandoffService.cs): a short-lived, single-use, purpose-scoped token signed with the same Data Protection key ring CredentialProtector already persists to disk (ITimeLimitedDataProtector, ~60s lifetime). CrudAdmin's Databases page and the Tenant Portal's own Databases tab both surface this as one-click buttons (Endpoints/CrossAppHandoffEndpoints.cs, Endpoints/TenantPortalEndpoints.cs). Consumers verify independently — no compiled dependency on this package required, just the documented purpose string ("CrudAdmin.CrossAppHandoff.v1") and JSON claim shape. Also stamps a plain-string ctx.Items identity bridge (CrudAdmin.Identity.AuthType/SubjectId/TenantId/DatabaseKey, Middleware/CrudAuthMiddleware.cs) after every successful /api/v* authentication, so an add-on package's own middleware can read the caller's identity the same way, with zero coupling.

🎭 Built-in roles

Role Permission set Risk Recommendation
Owner *.* 🛑 Destructive (total access) Reserve for true super-admins — auto-inherits all future destructive perms
Editor *.create, *.read, *.update, *.delete ✓ Safe Recommended default for power users
Writer *.read, *.create, *.update Standard Create + edit, no delete
Reader *.read Standard View-only

Why Editor exists

The wildcard *.* (held by Owner) literally means "every permission, including future ones." When new destructive permissions are added (e.g. database.bootstrap, database.config), Owner inherits them automatically. Editor explicitly lists the four CRUD actions, so it cannot accidentally accumulate destructive scope as the package evolves.

For most users, Editor is the right choice — assign Owner only when you genuinely want a role to grow with every new permission ever added.

Versions

  • 1.6.0CrossAppHandoffService + plain-string identity bridge (enables WebSvc.RateLimitAdmin's and WebSvc.SqliteAdmin's auto-login handoff), cross-app handoff endpoints on Databases/Tenant Portal.
  • 1.5.0 — Tenant Sessions admin page (force-revoke a tenant's active portal session).
  • 1.4.0 — Tenant self-service Settings tab + cross-app SSO exchange (/api/tenant/sso/exchange, /tenant/sso).
  • 1.3.0 — first-run /setup wizard; the default admin/admin@123 seed was removed.
  • 1.1.0–1.2.0 — MySQL support for the admin registry (IAdminDbConnectionFactory/SqlDialect), /admin/migrate-mysql migration wizard.

Further reading

  • docs/TENANT-SELF-SERVICE-REQUIREMENTS.md — the original self-service planning doc; see its status banner for what shipped as-specified vs. what shipped a different way (the Tenant Portal above) vs. what's still genuinely open (a REST role-export endpoint).
  • docs/BUG-DUPLICATE-GLOBAL-SETTINGS.md — resolved; kept as the record of why UpsertSetting does an explicit check-then-write instead of relying on ON CONFLICT.

© Narender Kumar

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.7.0 29 8/27/2026
1.6.0 52 8/26/2026
1.5.0 63 8/26/2026
1.4.0 61 8/26/2026
1.3.0 63 8/26/2026
1.2.0 55 8/26/2026
1.1.0 63 8/26/2026
1.0.9 81 8/24/2026
1.0.8 116 8/3/2026
1.0.7 117 8/3/2026
1.0.1 120 5/28/2026
1.0.0 126 5/27/2026