Offline (air-gapped) activation
A machine with intermittent connectivity doesn’t need file-based activation — the .NET SDK caches the license on disk and validates it offline for as long as the offline-grace policy allows. This page is for machines that never connect: activation and lease renewal travel as files.
Everything rests on one trust anchor: license artifacts are signed with the
provider’s key, and the device verifies them with the public key you shipped —
no network required. The public key is safe to ship: it can verify, not mint, so
carrying it on the device grants an attacker nothing. What is worth protecting
is the cached license itself once it lands on disk — see
at-rest encryption,
which the offline flow gets automatically since it uses the same LicenseFileStore.
How it works
Section titled “How it works”- On the device — the SDK writes an activation request file (activation code, fingerprint, application info).
- Carry it out — USB stick, one-way transfer, whatever your site allows.
- In the portal — an operator uploads the request under Offline activation; the server runs the normal activation pipeline and returns a signed response file.
- Carry it back — return the response file to the device.
- On the device — the SDK imports the response, verifies the signature and installs the license.
Add-on package: Revenusion.Oclavex.Client.OfflineStore (alongside
Client.LicenseConsumer).
Build the request on the device
Section titled “Build the request on the device”using Revenusion.Oclavex.Client.LicenseConsumer.Features.OfflineActivation;
var request = new OfflineActivationRequestBuilder() .WithActivationCode("ABC123-DEF456-GHI789") .WithFingerprint(nodeIdProvider) .WithApplicationInfo(applicationInfoProvider) .Build();
await OfflineActivationRequestWriter.WriteToFileAsync(request, @"D:\transfer\activation-request.json");The fingerprint provider is the same one the online flow uses — including per-component hashes, which are included in the request.
Issue the response
Section titled “Issue the response”In the portal, open Offline activation, upload the request file, and download
the signed response. From your own backend, the same operation is
POST /api/v1/provision/operational/activations/offline/issue.
The license must have Allow offline activation turned on in its license options
(see policies); it is off by default.
While it is off, the request is refused with 403
license.forbidden_by_policy and no seat is taken. Online activation of the same
license is not affected. Turning it off stops new activations by file; a device that
is already activated keeps uploading usage and renewing its lease. To cut it off,
disable the entitlement.
A product past its End of life refuses a
device that has never activated the license the same way, online and by file, with 403
license.product_end_of_life.
Submitting a byte-identical request file twice within a short server-side window returns the same signed bytes; a re-export from the device produces a fresh signature. A stronger guarantee holds at the session level: the same device (fingerprint) re-activating reuses its existing session, so a re-issued response file — however it was produced — can never consume a second seat.
Import on the device
Section titled “Import on the device”using Revenusion.Oclavex.Client.LicenseConsumer.Features.OfflineActivation;
var importer = new OfflineActivationResponseImporterBuilder() .WithFingerprint(nodeIdProvider) // required: refuses a license issued for another device .WithLicenseStore(licenseStore) .WithPublicKeyProvider(publicKeyProvider) .WithLicenseService(licenseService) // optional: refreshes the in-memory cache too .Build();
var result = await importer.ImportAsync(@"D:\transfer\activation-response.json");if (!result.IsSuccess) throw new InvalidOperationException(result.ErrorMessage);The importer verifies the envelope signature against the pinned public key before
touching the license store. A file it refuses (a bad signature, another device’s
license, an expired response) comes back as a failed result that says why, not as an
exception; on success result.Value is the imported license. From here the
application runs as if it had activated online.
The usage and lease loop
Section titled “The usage and lease loop”Air-gapped machines accumulate usage locally (FileTransactionStore).
Periodically, swap files again to upload usage and renew the lease:
-
Export on the device:
using Revenusion.Oclavex.Client.LicenseConsumer.Services.Store;var exporter = new LicenseZipFileExporter(@"D:\transfer\usage-export.zip", licenseStore, transactionStore);await exporter.ExportAsync(); -
Upload in the portal — Offline activation → Ingest transactions — and download the signed receipt. (API:
POST /api/v1/provision/operational/usage/offline/ingest.) The server records the usage, extends the lease, and wraps a refreshed license in the receipt. -
Import the receipt on the device:
using Revenusion.Oclavex.Client.LicenseConsumer.Features.OfflineActivation;var importer = new OfflineTransactionReceiptImporterBuilder().WithFingerprint(nodeIdProvider) // required: refuses a license issued for another device.WithTransactionStore(transactionStore).WithPublicKeyProvider(publicKeyProvider).WithLicenseService(licenseService).Build();var result = await importer.ImportAsync(@"D:\transfer\usage-receipt.json");It returns the same kind of result as the activation import. On success the refreshed license is installed first, then the uploaded transactions are purged from the local log — if anything fails before the purge, the result is failed and the log stays intact for retry.
Repeat the swap on whatever cadence the entitlement’s lease window requires, and an air-gapped fleet stays licensed and metered indefinitely. Re-uploading an export is safe: usage already recorded is not counted twice.
Operational notes
Section titled “Operational notes”- The whole loop is operator-driven through the portal in this release — there is no end-user self-service for offline activation.
- The request file is not secret (it contains hashes, not raw device traits), but treat response and receipt files as license material: they’re single-purpose, device-bound, and verified by signature on import.