Offline Licensing

Licensing Features

Offline Activation

Offline activation lets customers activate a license key on a machine that has no internet access. Instead of calling the public API, the customer presents a signed offline token that was generated for their specific device by a Company Admin.

How it works

  1. Customer generates their hardware fingerprint (HWID) and sends it to you via email / support portal.
  2. Admin opens the license in PermitCore → scrolls to Offline Activation Tokens → clicks Generate Token.
  3. Admin enters the Device ID, optional device name, and how long the token should be valid (1–365 days).
  4. A signed token is shown once — admin copies and sends it to the customer.
  5. Customer's application calls ActivateOffline(token) in your SDK. The SDK verifies the ECDSA signature, expiry, and device binding, then stores the token locally.
  6. On every subsequent launch, the SDK verifies the cached token offline — no internet needed.
The offline token is verified using your tenant's ECDSA P-256 public key. The public key is available at GET /api/v1/{tenantSlug}/public-key — the SDK uses it for verification; provide or cache it before disconnecting. Distribute the trusted public key to an air-gapped machine before activation. Offline verification works only until the token expires; the machine cannot discover revocations while disconnected.

Step-by-step in the Admin Panel

The token and the public key come from two different places in the admin panel — do this in order, since the token is worthless to a customer without your real public key to verify it against.

1
Export your signing public key (once, or after rotation)
Go to Settings → Security → Business Continuity. Click Export Signing Key. This downloads the current ECDSA P-256 public key — safe to embed in customer applications or hand out directly, since it can only verify tokens, never create them. Skip this step only if you already have the current key saved from a previous export.
2
Get the customer's Device ID
The customer's application calls the SDK's hardware-fingerprint helper (e.g. GetHardwareId()) and sends you the resulting string — by email, support ticket, or an in-app "Copy Device ID" button you build. This is the value the token gets bound to.
3
Generate the token
Open the customer's license: Licenses → [find the license] → View. Scroll to Offline Activation Tokens and click Generate Token. Paste the Device ID from step 2, optionally name the device (e.g. "Warehouse PC 3"), and choose how many days the token stays valid (1–365).
4
Copy the token — shown once
The signed pc_offline_v1.… string is displayed exactly once. Copy it now and send it to the customer alongside the public key from step 1 (not the token alone — the customer's app needs both to verify).
5
Customer activates offline
The customer's application calls the SDK's offline-activate function with the token and your public key (see the SDK code below). From then on it verifies the cached token locally on every launch — see "What the SDK does" below.
"Invalid signature" almost always means the wrong public key. Every downloadable SDK demo ships with a pre-filled sample public key and token pair purely to illustrate the fields — pasting a real token from your own tenant against that sample key will always fail signature verification, by design. Replace both fields with your own tenant's real public key (step 1 above) and a token generated for the actual device before testing.

Token format

Tokens have the format pc_offline_v1.<payload>.<signature>:

PartWhat it contains
pc_offline_v1Version prefix — validated first by the SDK
<payload>Base64URL-encoded JSON: tokenId, licenseKeyHash, deviceId, productName, expiresAt, …
<signature>Base64URL-encoded ECDSA P-256/SHA-256 signature over the UTF-8 bytes of the base64url payload string

What the SDK does

  1. Split on ., check prefix is pc_offline_v1
  2. Fetch (or load cached) tenant public key from /api/v1/{slug}/public-key
  3. Verify ECDSA signature — reject if invalid or tampered
  4. Check expiresAt > now — reject if expired
  5. Check deviceId matches local hardware fingerprint — reject if different machine
  6. Store token on disk — verified offline on every future launch
All six official SDKs implement offline token verification natively — no manual crypto required in your app. The critical implementation detail every SDK matches exactly: the server signs with ECDSA P-256 / SHA-256, IEEE P1363 raw signature format (a 64-byte r‖s concatenation, not ASN.1 DER) over the UTF-8 bytes of the base64url payload string.
C# (.NET SDK)
var client = new PermitCoreClient("https://your-domain.com");
var publicKey = /* fetched once from GET /api/v1/{slug}/public-key, then cached */;

// Offline activate (customer sent you the token) — persists to local disk
var result = PermitCoreClient.ActivateOffline(offlineToken, publicKey, hwid);

// On every subsequent launch — no internet needed
var result = PermitCoreClient.ValidateOffline(hwid);
Python (Python SDK)
# pip install cryptography  (lazy-imported — base client stays dependency-free)
result = PermitCoreClient.activate_offline(offline_token, public_key, hwid)

# On every subsequent launch — no internet needed
result = PermitCoreClient.validate_offline(hwid)
Node.js / TypeScript
const result = client.activateOffline(offlineToken, publicKey, hwid);

// On every subsequent launch — no internet needed
const result = client.validateOffline(hwid);
PHP
$result = $client->activateOffline($offlineToken, $publicKey, $hwid);

// On every subsequent launch — no internet needed
$result = $client->validateOffline($hwid);
Java
OfflineTokenResult result = client.activateOffline(offlineToken, publicKey, hwid);

// On every subsequent launch — no internet needed
OfflineTokenResult result = client.validateOffline(hwid);
C++
auto result = client.activate_offline(offline_token, public_key, hwid);

// On every subsequent launch — no internet needed
auto result = permitcore::PermitClient::validate_offline(hwid);

Revoking a token

To revoke an offline token, go to the license detail page → Offline Activation Tokens → click the ban icon next to the token. The token is immediately marked as revoked in the database.

Revoking is soft enforcement: the SDK can optionally call POST /api/v1/offline/verify to check revocation status when online. Strictly offline deployments won't see revocations until the token naturally expires. Use short expiresInDays values (e.g. 30–90 days) for tighter control.

Design trade-off: Offline activation cannot be instantly revoked on an air-gapped machine — the token must expire. Set short validity periods (30–90 days) for sensitive deployments. For perpetual licenses, use annual renewal tokens.

Optional server-side verification

When the customer's machine has internet access, your SDK can also call the server to check for revocation:

Request: POST /api/v1/offline/verify
{
  "token": "pc_offline_v1.eyJ2ZXJzaW9uIjoxLCJ..."
}
Example response
{
  "isValid":     true,
  "tokenId":     "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "productName": "Acme Video Editor Pro",
  "deviceId":    "a3f8d2b1c9e4...",
  "expiresAt":   "2026-08-29T00:00:00Z",
  "message":     "Token valid."
}

Security properties

PropertyHow it's achieved
Tamper-proofECDSA P-256 signature — any modification invalidates the signature
Device-boundToken payload includes deviceId — SDK rejects tokens for other machines
Time-limitedexpiresAt checked by both SDK and server verify endpoint
RevocableTokenId stored server-side — checked via /offline/verify when online
Public key distributionPublic key is per-tenant, fetched once from /api/v1/{slug}/public-key