TAF.Identity.SDK
1.0.2
dotnet add package TAF.Identity.SDK --version 1.0.2
NuGet\Install-Package TAF.Identity.SDK -Version 1.0.2
<PackageReference Include="TAF.Identity.SDK" Version="1.0.2" />
<PackageVersion Include="TAF.Identity.SDK" Version="1.0.2" />
<PackageReference Include="TAF.Identity.SDK" />
paket add TAF.Identity.SDK --version 1.0.2
#r "nuget: TAF.Identity.SDK, 1.0.2"
#:package TAF.Identity.SDK@1.0.2
#addin nuget:?package=TAF.Identity.SDK&version=1.0.2
#tool nuget:?package=TAF.Identity.SDK&version=1.0.2
TAF.Identity.SDK
The client for IdentityService, for the services that need to ask it things.
Every other TAF service ships an SDK — Metadata, CRUD, Kibana, Blueprint, Trigger, CodeExecutor, FileManager, Report, Template, WorkflowEngine, Notification, Approval. Identity did not, so each consumer wrote its own client. This is what that cost:
| Consumer | Hand-written client | What was wrong |
|---|---|---|
taf_crud |
EntitlementResolverClient |
called a route that did not exist, sent a header nothing reads, and its base URL was set in no config file for any environment |
taf_backgroundjobexecutors |
IdentityBillingClient |
read the payload from value where the service sends result, so every sweep reported null counts |
None of those failed loudly. The entitlement client treats any error as "no opinion" and allows the request, so licensing enforcement was off for every tenant with nothing in any log to say so. The scheduler's sweeps genuinely ran; only their results vanished.
A path is a string, a header name is a string, and a wrong string does not break a build. This package exists so those strings live in one place, next to the service that serves them.
Install
<PackageReference Include="TAF.Identity.SDK" Version="1.0.1" />
Register
builder.Services.AddIdentitySdk(builder.Configuration);
{
"IdentityService": {
"BaseUrl": "http://identity.internal:8080", // required — validated at startup
"ApiKey": "", // optional — falls back to ServiceAuth:ApiKey
"TimeoutSeconds": 5, // entitlement lookups sit on the request path
"SweepTimeoutSeconds": 600, // sweeps are long synchronous calls by design
"EntitlementCacheSeconds": 60 // bounds how long a lapsed plan keeps working
}
}
BaseUrl is validated at startup, not on first use. The client this replaced read its URL inside an
AddHttpClient lambda, which runs when the client is first resolved — so a missing value produced a
healthy-looking deploy followed by a failure on every request.
Use
Entitlements — "did this tenant pay for it?"
public sealed class MyGate(IIdentityEntitlementClient identity)
{
public async Task<bool> IsAllowedAsync(Guid tenantId, Guid appId, Guid? appObjectId, Guid? moduleId)
{
var plan = await identity.ResolveAsync(tenantId, appId);
if (!SubscriptionStateMap.AllowsRead(plan.State))
return false;
return plan.GetAccessForObject(appObjectId, moduleId, ancestry) != FeatureAccessLevel.None;
}
}
ResolveAsync never throws and never denies. An unreachable Identity, an unreadable body or no
subscription all return PlanEntitlements.Ungated, which permits everything. Entitlement is a commercial
control, not a security boundary — tenant isolation and permissions are enforced elsewhere and do not depend
on this answering.
The consequence deserves stating plainly, because it is what let a broken client survive for months: when this is misconfigured, everything is allowed and the caller logs nothing alarming. Watch for the SDK's own warning, which names the status and the URL it tried.
Lifecycle sweeps — for the scheduler
var result = await identityLifecycle.RunReconcileAsync(ct);
logger.LogInformation("Reconcile repaired {Repaired} of {Scanned}.", result?.Repaired, result?.LedgerRowsScanned);
Unlike entitlements, these do surface failures. A sweep that did not run is something an operator needs
to know about, and there is no "carry on regardless" answer available. A rejected credential throws
IdentityServiceUnauthorizedException and is deliberately not retryable: it will be rejected identically
on every attempt, and burying it in retry noise is how a silently disabled billing sweep goes unnoticed for a
week.
Routes
IdentityRoutes holds every path. IdentityService's own ApiRoutes is defined from these constants, so the
route a controller serves and the route a consumer requests cannot drift apart without breaking a build on
one side or the other.
| Product | Versions 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. |
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- TAF.Infra.Authentication (>= 1.1.1)
- TAF.Infra.Licensing (>= 1.6.0)
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.0.2 | 130 | 8/5/2026 |