RTI.Validator
1.0.3
dotnet add package RTI.Validator --version 1.0.3
NuGet\Install-Package RTI.Validator -Version 1.0.3
<PackageReference Include="RTI.Validator" Version="1.0.3" />
<PackageVersion Include="RTI.Validator" Version="1.0.3" />
<PackageReference Include="RTI.Validator" />
paket add RTI.Validator --version 1.0.3
#r "nuget: RTI.Validator, 1.0.3"
#:package RTI.Validator@1.0.3
#addin nuget:?package=RTI.Validator&version=1.0.3
#tool nuget:?package=RTI.Validator&version=1.0.3
RTI.Validator
Client-side .NET library for validating and refreshing RTI software licenses.
Overview
RTI.Validator verifies that a license file (.lic) issued by the RTI License Service is authentic,
active, and within its offline grace period. On the first run it generates a device-bound ECDSA key
pair, registers the public key with the RTI License Service, and collects a hardware fingerprint.
On subsequent runs it validates the license locally and can transparently refresh it by signing a
request with the device private key.
Integration flow
1. Admin creates a ClientInstance in the backoffice
→ receives ClientInstanceId + ApplicationCode
2. Developer configures the library (see Configuration)
3. Application calls RegisterDeviceKeyAsync() on first run
→ generates device key pair (device.key)
→ registers public key with the RTI License Service
4. Admin issues the license (after key is registered)
→ downloads license.lic, places it next to the application
5. Application calls Validate() at startup and periodically
→ verifies signature, state, expiry, grace period
6. When result.NeedsRefresh == true, call TryRefreshAsync()
→ renews license.lic online
Prerequisites
The following values must be provided by the RTI administrator:
| Value | Required for | Description |
|---|---|---|
ApiBaseUrl |
Registration, Refresh | Base URL of the RTI License Service (e.g. https://api.your-domain.com) |
ClientInstanceId |
Registration, Refresh | GUID of the ClientInstance created for this installation |
ApplicationCode |
Registration | Application code used when the ClientInstance was created |
license.lic |
Validate | License file issued after key registration |
The server public key is fetched automatically from GET /api/v2.0/licenseservice/keys/server/public
during RegisterDeviceKeyAsync() and cached in device.state.
Installation
dotnet add package RTI.Validator
Configuration
Store sensitive values in your application configuration (environment variables, secrets manager,
or appsettings.json). Never hardcode them in source code.
appsettings.json example:
{
"RtiValidator": {
"ApiBaseUrl": "https://api.your-domain.com",
"ClientInstanceId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"ApplicationCode": "YourAppCode"
}
}
Usage
Setup
using RTI.Validator;
var options = new RtiLicenseValidatorOptions
{
LicenseFilePath = "license.lic",
ApiBaseUrl = configuration["RtiValidator:ApiBaseUrl"],
ClientInstanceId = Guid.Parse(configuration["RtiValidator:ClientInstanceId"]),
ApplicationCode = configuration["RtiValidator:ApplicationCode"]
};
IRtiLicenseValidator validator = new RtiLicenseValidator(options);
Step 1 — Register device key (first run only)
Call RegisterDeviceKeyAsync() once before the license is issued. Safe to call on every startup —
if already registered it returns AlreadyRegistered immediately without a network request.
var activation = await validator.RegisterDeviceKeyAsync();
if (!activation.IsSuccess)
{
Console.WriteLine($"Activation failed: {activation.FailureReason}");
Environment.Exit(1);
}
if (activation.Status == ActivationStatus.AlreadyRegistered)
Console.WriteLine("Device key already registered.");
else
Console.WriteLine("Device key registered successfully. Ask the admin to issue the license.");
After a successful registration, give the ClientInstanceId to the RTI administrator
so they can issue license.lic and send it to you.
Step 2 — Validate
Call Validate() at application startup (and periodically, e.g. once per hour):
var result = validator.Validate();
if (!result.IsValid)
{
Console.WriteLine($"License invalid: {result.FailureReason}");
Environment.Exit(1);
}
if (result.IsExpiringSoon)
Console.WriteLine($"License expires in {result.DaysUntilExpiry} day(s).");
if (result.NeedsRefresh)
{
var refresh = await validator.TryRefreshAsync();
if (!refresh.IsSuccess)
Console.WriteLine($"Refresh failed: {refresh.FailureReason}");
}
Dependency injection
services.AddSingleton<IRtiLicenseValidator>(new RtiLicenseValidator(options));
Activation result statuses
| Status | Meaning |
|---|---|
Success |
Key generated and registered on the server for the first time |
AlreadyRegistered |
Key was registered in a previous activation — no network call made |
ConfigurationError |
ApiBaseUrl, ClientInstanceId, or ApplicationCode is missing |
ServerUnreachable |
HTTP request to the API failed (network, timeout, TLS) |
ServerRejected |
API returned an unexpected error response |
Validation statuses
| Status | Meaning |
|---|---|
Valid |
License is valid |
LicenseFileNotFound |
license.lic does not exist at the configured path |
LicenseFileCorrupt |
File exists but cannot be parsed |
InvalidSignature |
Server signature verification failed — file may be tampered |
LicenseNotActive |
License state is not Active (e.g. Blocked, Suspended) |
NotYetValid |
Current date is before ValidFrom |
Expired |
Current date is after ValidTo |
GracePeriodExceeded |
No successful online validation within MaxOfflineDays |
ClockRollbackDetected |
System clock is behind the last recorded online validation |
Refresh result statuses
| Status | Meaning |
|---|---|
Success |
Refresh succeeded, new license.lic written to disk |
ConfigurationError |
Missing ApiBaseUrl, ClientInstanceId, or license file |
ServerUnreachable |
HTTP request to the API failed |
ServerRejected |
API returned a non-2xx response |
InvalidServerResponse |
Response body is not a valid license envelope |
Local files
| File | Purpose |
|---|---|
device.key |
Encrypted ECDSA P-256 private key — generated on first activation |
device.state |
Encrypted device state (fingerprint, last validation, monotonic counter) |
license.lic |
License envelope issued by the RTI License Service |
These files must not be deleted.
- Deleting
device.keyinvalidates the registered public key on the server and requires re-registration. - Deleting
device.stateresets the monotonic counter, which may trigger clock-rollback detection.
Security notes
device.keyanddevice.stateare written with OS-level protection. Do not include them in backups or source control (they are listed in.gitignore).- The server public key is fetched once during
RegisterDeviceKeyAsync()over HTTPS and stored indevice.state. It is never fetched again — tampering with the network after registration cannot substitute a different key. - The server signature on the
.licfile is verified on everyValidate()call. A tampered file will fail withInvalidSignature. - The monotonic counter in
device.statedetects system clock rollback attempts to extend the offline grace period.
Supported platforms
- Windows (.NET 9+) — DPAPI encryption for
device.keyanddevice.state - Linux (.NET 9+) — file permissions (
chmod 600) - macOS (.NET 9+) — file permissions (
chmod 600)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. 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. |
-
net9.0
- System.Security.Cryptography.ProtectedData (>= 10.0.5)
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 |
|---|