![]() |
VOOZH | about |
dotnet add package Tharga.Team.Service --version 3.0.4
NuGet\Install-Package Tharga.Team.Service -Version 3.0.4
<PackageReference Include="Tharga.Team.Service" Version="3.0.4" />
<PackageVersion Include="Tharga.Team.Service" Version="3.0.4" />Directory.Packages.props
<PackageReference Include="Tharga.Team.Service" />Project file
paket add Tharga.Team.Service --version 3.0.4
#r "nuget: Tharga.Team.Service, 3.0.4"
#:package Tharga.Team.Service@3.0.4
#addin nuget:?package=Tharga.Team.Service&version=3.0.4Install as a Cake Addin
#tool nuget:?package=Tharga.Team.Service&version=3.0.4Install as a Cake Tool
Server-side API-key authentication, authorization enforcement, controller registration, OpenAPI/Swagger setup, and audit logging for ASP.NET Core projects. Targets .NET 9.0 and .NET 10.0.
X-API-KEY header, validates against a store, and populates TeamKey, AccessLevel, and scope claims.AccessLevelProxy<T> enforces [RequireAccessLevel] on service methods via DispatchProxy.ScopeProxy<T> enforces [RequireScope] with audit logging.ITeamPrincipalAccessor (default: IHttpContextAccessor). AddThargaTeamBlazor swaps in a circuit-aware accessor (HttpContext when present, else AuthenticationStateProvider), so one [RequireScope]/[RequireAccessLevel] enforces both surfaces. Register a custom ITeamPrincipalAccessor to plug in another principal source.ApiKeyAdministrationService with key hashing. Configurable via ApiKeyOptions — see API key options.CompositeAuditLogger with ILogger and MongoDB backends. ⚠️ Stores to ILogger only by default — see Audit logging.IApiKeyLifecycleHandler — see Capturing the private token.IApiKeyAdministrationService (from Tharga.Team) to bring your own storage backend.using Tharga.Team;
using Tharga.Team.Service;
// Program.cs
builder.Services.AddThargaControllers();
builder.Services.AddAuthentication()
.AddThargaApiKeyAuthentication();
builder.Services.AddThargaApiKeys();
var app = builder.Build();
app.UseThargaControllers();
app.UseAuthentication();
app.UseAuthorization();
app.Run();
For infrastructure-level credentials that aren't tied to a team (MCP gatekeepers, CI/CD callers, cross-team admin tooling), use system keys — API keys with no TeamKey.
Create and manage them via the <SystemApiKeyView /> component in Tharga.Team.Blazor (gated by the Developer role), or programmatically via IApiKeyAdministrationService.CreateSystemKeyAsync(name, scopes, expiryDate, createdBy).
System keys authenticate through the same X-API-KEY header. The principal they produce carries the IsSystemKey=true claim and the explicit scopes granted at creation time — no TeamKey claim.
Protect system-only endpoints with the system policy:
app.UseThargaMcp().RequireAuthorization(ApiKeyConstants.SystemPolicyName);
The two policies are mutually exclusive: ApiKeyPolicy rejects system keys, SystemApiKeyPolicy rejects team keys.
Protect endpoints with the built-in policy:
[Authorize(Policy = ApiKeyConstants.PolicyName)]
[ApiController]
[Route("api/[controller]")]
public class MyController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
var teamKey = User.FindFirst(TeamClaimTypes.TeamKey)?.Value;
return Ok(new { teamKey });
}
}
Enforce access levels on services:
public interface IMyService
{
[RequireAccessLevel(AccessLevel.Viewer)]
IAsyncEnumerable<Item> GetAsync();
[RequireAccessLevel(AccessLevel.User)]
Task<Item> AddAsync(string name);
}
// Program.cs
builder.Services.AddScopedWithAccessLevel<IMyService, MyService>();
API key behaviour is configured via ApiKeyOptions (passed to AddThargaApiKeyAuthentication, or o.ApiKey under AddThargaPlatform):
| Option | Default | Purpose |
|---|---|---|
AdvancedMode |
false |
When false, keys are auto-created per team and only refresh/lock are exposed. When true, full CRUD (name, access level, roles, scope overrides, expiry). |
AutoKeyCount |
2 |
Number of keys auto-created per team in simple mode. |
AutoLockKeys |
false |
Lock keys immediately after creation so the raw value is shown only once. |
MaxExpiryDays |
365 |
Caps expiry for team and system keys. null = no cap. |
LastUsedThrottle |
1 min |
Minimum interval between LastUsedAt writes for a key (avoids a DB write per request). TimeSpan.Zero = stamp every request. |
MinKeyLength / MaxKeyLength |
24 / 32 |
Random alphanumeric length of the key secret (base62, ≈5.95 bits/char). The length is chosen at random in [Min, Max] per key. ~190-bit at the default 32; 43 ≈ 256-bit. Floor 24 (≈143-bit). |
AddThargaAuditLogging records mutations (team-service operations and API-key management) and authorization events via CompositeAuditLogger.
builder.Services.AddThargaAuditLogging(o =>
{
o.StorageMode = AuditStorageMode.MongoDB; // see gotcha below
o.RetentionDays = 90; // null (or <= 0) = keep forever
});
⚠️ Gotcha:
StorageModedefaults toLoggeronly, so the MongoDB-backedAuditLogViewstays empty until you setAuditStorageMode.MongoDB(orLogger | MongoDB).AuditStorageModeis a[Flags]enum.
| Option | Default | Notes |
|---|---|---|
StorageMode |
Logger |
[Flags]: Logger, MongoDB, or both. Set MongoDB to populate AuditLogView. |
CallerFilter / EventFilter |
Api\|Web / All |
[Flags] — which caller sources / event types to record. |
ExcludedActions / ExcludedEndpoints |
empty | Skip noisy actions (e.g. "read") or endpoints. |
RetentionDays |
90 |
int? → MongoDB TTL index (Timestamp_TTL). null or <= 0 = keep forever (no TTL index). Changing/removing the TTL on an existing collection may need a manual index drop. |
BatchSize / FlushIntervalSeconds |
100 / 5 |
Background MongoDB writer tuning. |
See the implementation guide for the full reference.
The private token is shown once and never persisted, logged, or exposed over an API. To capture it (e.g. to re-deliver a minted key), register an IApiKeyLifecycleHandler — it receives the token on create and recycle/regenerate, plus a tokenless delete signal:
public class MyHandler(ISecretProtector protector, IMyStore store) : IApiKeyLifecycleHandler
{
public Task OnApiKeyLifecycleAsync(ApiKeyLifecycleContext ctx) => ctx.Reason switch
{
ApiKeyLifecycleReason.Deleted => store.RemoveAsync(ctx.ApiKeyId),
_ => store.SaveAsync(ctx.ApiKeyId, protector.Protect(ctx.PrivateToken), ctx.TeamKey, ctx.Tags),
};
}
builder.AddThargaPlatform(o => o.AddApiKeyLifecycleHandler<MyHandler>());
A throwing handler propagates out of the originating operation (capture failures are not swallowed). You own whatever you capture — encrypt it at rest.
| Package | Description |
|---|---|
| Tharga.Team | Domain models and authorization primitives (plain .NET, WASM-safe) |
| Tharga.Team.Blazor | Team-specific Blazor UI components |
| Tharga.Blazor | Generic Blazor UI components |
| Tharga.Team.MongoDB | MongoDB persistence for teams and users |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 2 NuGet packages that depend on Tharga.Team.Service:
| Package | Downloads |
|---|---|
|
Tharga.Team.Blazor
Team management Blazor components for multi-tenant applications. Works with both Blazor Server and WebAssembly. |
|
|
Tharga.Platform.Mcp
Platform bridge for Tharga.Mcp. Provides Platform-backed IMcpContext, scope enforcement, audit logging, and authentication for MCP tool and resource invocations. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.4 | 115 | 6/14/2026 |
| 3.0.3 | 130 | 6/11/2026 |
| 3.0.2 | 136 | 6/4/2026 |
| 3.0.1 | 137 | 6/2/2026 |
| 3.0.0 | 120 | 6/2/2026 |
| 2.1.3 | 130 | 5/30/2026 |
| 2.1.2 | 132 | 5/29/2026 |
| 2.1.1 | 139 | 5/26/2026 |
| 2.1.0 | 136 | 5/18/2026 |
| 2.0.18 | 199 | 5/11/2026 |
| 2.0.17 | 138 | 5/10/2026 |
| 2.0.16 | 133 | 5/7/2026 |
| 2.0.15 | 155 | 4/29/2026 |
| 2.0.14 | 130 | 4/29/2026 |
| 2.0.13 | 139 | 4/21/2026 |
| 2.0.12 | 130 | 4/20/2026 |
| 2.0.11 | 158 | 4/18/2026 |
| 2.0.10 | 126 | 4/17/2026 |
| 2.0.9 | 115 | 4/17/2026 |
| 2.0.8 | 156 | 4/8/2026 |