Offline Licensing¶
A managed install can require a signed offline license that proves enterprise entitlement from a file alone, with no network access. The license is verified entirely offline, so it works in air-gapped sites. This page covers issuing, installing, and rotating the license, and the states an administrator should expect.
For the license document schema and an example, see the Policy Schema Reference. This page covers operation.
What the license is¶
The license is a JSON document at <app_data>/enterprise/license.json. It carries a License (schema version, license id, organization, issue date, an optional expiry, optional seat and device limits, and optional entitlements) plus a detached Ed25519 signature and the id of the anchor that signed it. It is signed by the same trust anchors distributed through the provisioning profile, so it needs no separate key material on the device.
The license is verified at startup and again every time the status surface is read. Because it is re-read fresh each time, an expiry takes effect without a restart, and replacing the file is picked up immediately.
The license gate is independent of policy¶
The license gate and policy enforcement are deliberately separate. An absent, expired, invalid, or over-limit license never unlocks the policy locks or the egress firewall. Doing so would be a downgrade attack: an attacker could drop the license file and watch the restrictions fall away. Instead, the policy locks and the egress allowlist stay fully enforced, and a non-valid license is surfaced as a prominent, localized banner that gates continued enterprise operation.
This means the license proves entitlement; it does not relax security. A device with no valid license keeps every policy restriction and simply shows the gated banner.
License states¶
The license state is reported in the license field of the enterprise status (get_managed_status, or GET /api/v1/enterprise/status). The field is omitted for an un-managed install. For a managed install it carries one of five states:
| State | Meaning | What the admin sees |
|---|---|---|
valid | Verified, unexpired, and covers this install. | No banner. Enterprise operation is enabled. |
expired | The signature verified, but expiresAt is in the past. | "Enterprise license expired" banner. |
over_limit | Verified and unexpired, but a seat or device limit cannot cover this install. | "Enterprise license over limit" banner. |
invalid | A file is present but failed verification (bad or forged signature, out-of-range schema, unknown or expired anchor, or an unreadable file). | "Enterprise license invalid" banner. |
absent | No license file is present. | "Enterprise license missing" banner. |
Only valid permits continued enterprise operation. Every other state shows the gated banner, which reads in the form "license expired or missing, contact your administrator", and notes that the policy settings stay enforced. The license signature and any key material are never returned in the status; the surface is secret-free by construction.
Seat and device limits¶
The optional seatLimit and deviceLimit are surfaced for display, but the offline gate can only assert a floor. It enforces that the license must cover at least this single install: a limit below one, or a device-limited license on an install with no device identity, is over_limit. Org-wide seat and device counts are tallied by the management server, not by the offline gate. Use the limits to record the entitlement; rely on the management server for fleet-wide counting.
Issue a license¶
A license is signed with the organization's Ed25519 signing key, the same root of trust as the policy server and the trust anchors you distribute. Sign the License document over its canonical bytes with that key, set anchorId to the matching anchor id, and distribute the resulting SignedLicense JSON as a file.
{
"license": {
"schemaVersion": 1,
"licenseId": "acme-2026",
"organization": "Acme Corp",
"issuedAt": "2026-01-01T00:00:00Z",
"expiresAt": "2027-01-01T00:00:00Z",
"seatLimit": 250,
"deviceLimit": 250,
"entitlements": ["premium_models"]
},
"signature": "<base64 Ed25519 signature over the canonical license bytes>",
"anchorId": "acme-policy-anchor"
}
Omit expiresAt for a perpetual license. Omit the limits to record no seat or device cap. The anchorId must match an anchor the device trusts (one you distributed in the provisioning profile), or verification fails as invalid.
Install and rotate a license¶
Installing a license is a file drop. Place the signed JSON at <app_data>/enterprise/license.json on the device:
- Linux:
~/.local/share/ai.backend.go/enterprise/license.json - Windows:
%APPDATA%\ai.backend.go\enterprise\license.json - macOS:
~/Library/Application Support/ai.backend.go/enterprise/license.json
Deliver the file the same way you deliver the provisioning profile: an MDM file payload, a repackaged installer, or a managed-file drop. The license is non-secret (it carries no private key), so it is safe to deploy at scale.
To rotate a license, before expiry, replace the file with a newly signed one. The new license is read on the next status check, so the change takes effect without a restart. Plan the rotation ahead of expiresAt so a device never sits in the expired state: sign the next license, deploy it, and confirm the Organization tab shows valid again.
Verify¶
Confirm the license state from the app or the status surface.
- The Organization settings tab shows the license badge. A managed install with a good license shows
validand no banner. - The status surface reports the
licensestate underlicense. - After deploying a renewed license, confirm the state returns to
validand the gated banner disappears.
Next steps¶
- Combine with an offline site in Air-Gapped Deployment.
- Distribute the license alongside the profile in Device Enrollment and Trust Anchors.
- Schedule renewals and key rotation in the Administrator Guide.