C# SDK (Auris.Licensing)
Auris.Licensing is the official .NET client library for the Auris Licensing module. It targets netstandard2.0, has zero external dependencies (no NuGet references — manual JSON parsing throughout), and implements the full licensing surface: key validation, device activation and deactivation, metered usage recording, floating seat checkout, and offline activation.
This package covers the Licensing module only. It does not provide IAM functionality (user authentication, OIDC, roles, MFA, or the Management API). For full IAM coverage in .NET applications use the Auris REST API directly with a standard OAuth2 library, or reach out for integration guidance.
Target framework: netstandard2.0
External dependencies: none
Namespace: Auris.Licensing
Installation
dotnet add package Auris.LicensingOr add the reference manually in your project file:
<PackageReference Include="Auris.Licensing" Version="1.0.0" />AurisLicenseClient
AurisLicenseClient is the single entry point for all licensing operations. It implements IDisposable — wrap it in a using block or register it as a singleton in your DI container.
Constructor
using Auris.Licensing;
var client = new AurisLicenseClient(
tenantDomain: "auth.yourdomain.com", // required — your Auris tenant domain, without https://
timeoutSeconds: 10 // optional — HTTP timeout (default: 10)
);The client sets the base URL to https://{tenantDomain} and attaches the x-tenant header to every outbound request. No API key is required at the SDK level — the tenant domain identifies the tenant.
Key Validation
ValidateAsync
Validates a license key against the Auris API and returns the full validation result, including the licensee, plan, capacity counters, enabled features, and entitlement metadata.
ValidationResult result = await client.ValidateAsync("LIC-XXXX-XXXX-XXXX");
Console.WriteLine(result.Valid); // bool
Console.WriteLine(result.PlanName); // string
Console.WriteLine(result.Licensee.Id); // string
Console.WriteLine(result.Licensee.Type); // string ("user" or "org")Signature:
Task<ValidationResult> ValidateAsync(string key, CancellationToken ct = default)Device Activation
ActivateAsync
Activates a license key on a specific device fingerprint. The fingerprint uniquely identifies the machine (you generate it — typically a hash of hardware identifiers). An optional human-readable name can be attached to the device record in the Auris console.
Device device = await client.ActivateAsync(
key: "LIC-XXXX-XXXX-XXXX",
fingerprint: "sha256-of-machine-id",
name: "Alice's Workstation" // optional
);
Console.WriteLine(device.Id); // string — device record ID in Auris
Console.WriteLine(device.Fingerprint); // stringSignature:
Task<Device> ActivateAsync(
string key,
string fingerprint,
string? name = null,
CancellationToken ct = default
)DeactivateAsync
Releases a device activation, freeing the slot for reuse on another machine.
await client.DeactivateAsync(
key: "LIC-XXXX-XXXX-XXXX",
fingerprint: "sha256-of-machine-id"
);Signature:
Task DeactivateAsync(string key, string fingerprint, CancellationToken ct = default)Metered Usage
RecordUsageAsync
Records consumption of a metered metric (for example, API calls processed, documents generated, or gigabytes stored). If amount is omitted the API increments the counter by 1.
UsageRecord record = await client.RecordUsageAsync(
key: "LIC-XXXX-XXXX-XXXX",
metric: "api_calls",
amount: 50L // optional — defaults to 1
);
Console.WriteLine(record.Metric); // string
Console.WriteLine(record.Amount); // long
Console.WriteLine(record.Timestamp); // DateTimeOffsetSignature:
Task<UsageRecord> RecordUsageAsync(
string key,
string metric,
long? amount = null,
CancellationToken ct = default
)GetUsageAsync
Retrieves all metered usage counters for a license key, keyed by metric name.
Dictionary<string, UsageMetric> usage = await client.GetUsageAsync("LIC-XXXX-XXXX-XXXX");
if (usage.TryGetValue("api_calls", out var metric))
{
Console.WriteLine($"Used: {metric.Used} / {metric.Max}");
Console.WriteLine($"Resets at: {metric.ResetsAt}");
Console.WriteLine($"Period: {metric.Period}"); // "day", "month", or "forever"
}Signature:
Task<Dictionary<string, UsageMetric>> GetUsageAsync(string key, CancellationToken ct = default)Feature Flags
CheckFeatureAsync
Returns true if the license grants access to the named feature. Use this for gating functionality that is enabled or disabled per plan.
bool hasAdvancedReporting = await client.CheckFeatureAsync(
key: "LIC-XXXX-XXXX-XXXX",
feature: "advanced_reporting"
);
if (!hasAdvancedReporting)
{
// Disable or hide the feature in the UI
}Signature:
Task<bool> CheckFeatureAsync(string key, string feature, CancellationToken ct = default)Floating Seats
Floating seats allow a fixed number of concurrent users to share a single license. Users check out a seat when they begin work and check it back in when done. An optional lease duration limits how long a seat stays checked out without a heartbeat.
CheckoutAsync
Reserves a seat for the given user. Returns the Seat record including its expiry time.
Seat seat = await client.CheckoutAsync(
key: "LIC-XXXX-XXXX-XXXX",
userId: "usr_alice",
leaseDurationMin: 60 // optional — lease expires after 60 minutes without heartbeat
);
Console.WriteLine(seat.UserId); // string
Console.WriteLine(seat.ExpiresAt); // DateTimeOffset?Signature:
Task<Seat> CheckoutAsync(
string key,
string userId,
int? leaseDurationMin = null,
CancellationToken ct = default
)CheckinAsync
Releases a previously checked-out seat, freeing it immediately for another user.
await client.CheckinAsync(
key: "LIC-XXXX-XXXX-XXXX",
userId: "usr_alice"
);Signature:
Task CheckinAsync(string key, string userId, CancellationToken ct = default)HeartbeatAsync
Extends the lease on an active seat. Call this periodically (for example, every 15 minutes) from long-running sessions to prevent the seat from expiring and being reclaimed.
Seat seat = await client.HeartbeatAsync(
key: "LIC-XXXX-XXXX-XXXX",
userId: "usr_alice",
leaseDurationMin: 60 // optional — reset the lease to another 60 minutes
);Signature:
Task<Seat> HeartbeatAsync(
string key,
string userId,
int? leaseDurationMin = null,
CancellationToken ct = default
)Offline Licensing
Offline activation is a two-step process: the client generates a request payload, the user submits it to the Auris portal to obtain a signed JWT response, and the client validates that response locally. No network call is made during ValidateOfflineResponse — the JWT signature is not verified; only the exp claim is checked.
GenerateOfflineRequest
Produces a base64-encoded request payload that the user submits to the Auris console to obtain an offline license response. This method is synchronous.
string requestPayload = client.GenerateOfflineRequest(
key: "LIC-XXXX-XXXX-XXXX",
fingerprint: "sha256-of-machine-id",
machineName: "Alice's Workstation" // optional
);
// Present requestPayload to the user. They paste it into the Auris portal
// and download the response string.Signature:
string GenerateOfflineRequest(string key, string fingerprint, string? machineName = null)ValidateOfflineResponse
Decodes and validates the JWT returned by the Auris portal. Throws AurisLicensingException if the token is expired or cannot be decoded.
string responseJwt = /* string obtained from the Auris portal */;
ValidationResult result = client.ValidateOfflineResponse(responseJwt);
Console.WriteLine(result.Valid);
Console.WriteLine(result.PlanName);Signature:
ValidationResult ValidateOfflineResponse(string responseData)ASP.NET Example
A complete example validating a license key in an ASP.NET Core Minimal API, with the client registered as a singleton and cancellation token forwarding:
// Program.cs
using Auris.Licensing;
var builder = WebApplication.CreateBuilder(args);
// Register as a singleton — AurisLicenseClient is thread-safe
builder.Services.AddSingleton(new AurisLicenseClient(
tenantDomain: builder.Configuration["Auris:TenantDomain"]!,
timeoutSeconds: 10
));
var app = builder.Build();
app.MapPost("/api/activate", async (
ActivationRequest req,
AurisLicenseClient licenseClient,
CancellationToken ct
) =>
{
try
{
// 1. Validate the key first
var validation = await licenseClient.ValidateAsync(req.LicenseKey, ct);
if (!validation.Valid)
return Results.BadRequest(new { error = "License key is not valid." });
// 2. Activate this device
var device = await licenseClient.ActivateAsync(
key: req.LicenseKey,
fingerprint: req.MachineFingerprint,
name: req.MachineName,
ct: ct
);
return Results.Ok(new
{
activated = true,
deviceId = device.Id,
plan = validation.PlanName,
licensee = validation.Licensee.Id,
});
}
catch (AurisLicensingException ex) when (ex.StatusCode == 422)
{
return Results.UnprocessableEntity(new { error = "Device limit reached for this license." });
}
catch (AurisLicensingException ex)
{
return Results.Problem(
title: "Licensing error",
detail: ex.Message,
statusCode: ex.StatusCode
);
}
});
app.MapPost("/api/validate", async (
ValidateRequest req,
AurisLicenseClient licenseClient,
CancellationToken ct
) =>
{
var result = await licenseClient.ValidateAsync(req.LicenseKey, ct);
return Results.Ok(new
{
valid = result.Valid,
plan = result.PlanName,
licensee = result.Licensee?.Id,
});
});
app.Run();
record ActivationRequest(string LicenseKey, string MachineFingerprint, string? MachineName);
record ValidateRequest(string LicenseKey);Model Types
| Type | Properties |
|---|---|
ValidationResult | Valid (bool), PlanName (string), Licensee (Licensee), Capacity (CapacityCounter), Features (string[]), Metadata (Dictionary) |
Licensee | Id (string), Type (string) |
CapacityCounter | Used (int), Max (int) |
UsageMetric | Used (long), Max (long?), Period (string), ResetsAt (DateTimeOffset?) |
Device | Id (string), Fingerprint (string), Name (string?), CreatedAt (DateTimeOffset) |
UsageRecord | Metric (string), Amount (long), Timestamp (DateTimeOffset) |
Seat | UserId (string), CheckedOutAt (DateTimeOffset), ExpiresAt (DateTimeOffset?) |
Error Handling
All async methods throw AurisLicensingException on any non-2xx response. The synchronous methods (GenerateOfflineRequest, ValidateOfflineResponse) throw AurisLicensingException for decoding failures.
using Auris.Licensing;
try
{
var result = await client.ValidateAsync("LIC-XXXX-XXXX-XXXX");
}
catch (AurisLicensingException ex)
{
Console.Error.WriteLine($"HTTP {ex.StatusCode}: {ex.Message}");
// StatusCode examples:
// 404 — key not found
// 422 — device limit reached, usage limit exceeded
// 410 — key expired or revoked
// 503 — Auris API unreachable (network error wrapped as 0)
}| StatusCode | Meaning |
|---|---|
| 404 | License key not found |
| 410 | License key expired or revoked |
| 422 | Validation failed (device limit, usage cap, feature not enabled) |
| 0 | Network or serialization error (no HTTP response received) |
Related Pages
- Swift SDK — Licensing client for Apple platform applications
- JavaScript SDK — Full IAM SDK for browsers and Node.js
- Next.js SDK — Server-side IAM helpers for Next.js
- Licensing Guide — Key types, capacity counters, metered billing, and floating seats