What happens between your installer and an active license

The client calls the public licensing API over HTTPS, caches the signed token, and verifies offline on each start. It only goes online when the token expires or it needs to see a revocation.

Desktop app
license_key + device id
HTTPS →
UnionUser API
verify, activate, sign token
→
PostgreSQL
licenses, devices, audit

Optional: in self-hosted mode, both the service and the database run in your environment.

Three paths

Three actions cover the whole integration

1. First activation

The user enters a key, the client reports a device id, and the server claims a slot atomically and returns a signed token.

POST /api/v1/license/activate

2. Startup verification

Verify offline on every start. Call verify when the token nears expiry or you need to observe a revocation.

POST /api/v1/license/verify

3. Auto-update

Point the updater at the release feed. Add the license key when the feed is gated; artifacts are signed independently.

GET /releases/{product_slug}/*
Device fingerprint

Stable, irreversible and privacy-safe

A device id distinguishes machines, not people. Read the native machine identifier, hash it before upload, and disclose it in your privacy policy.

  • Windows: MachineGuid in HKLM\SOFTWARE\Microsoft\Cryptography
  • macOS: IOPlatformUUID from ioreg
  • Linux: /etc/machine-id
  • Hash before upload: sha256("app:" + raw).slice(0, 32)
fingerprint.jsexample
import { createHash } from 'node:crypto';
import { execSync } from 'node:child_process';

const raw = process.platform === 'win32'
  ? execSync('reg query "HKLM\\SOFTWARE\\Microsoft\\Cryptography" /v MachineGuid').toString()
  : execSync('cat /etc/machine-id').toString();

const deviceId = 'wm-' + createHash('sha256')
  .update('app:' + raw.trim()).digest('hex').slice(0, 32);
Error handling

Map error codes to actions users understand

CodeMeaningSuggested action
ACTIVATION_LIMITNo device slot leftSend the customer to the portal to release a device
LICENSE_EXPIREDLicense expiredShow renewal; keep read-only features available
LICENSE_SUSPENDEDLicense suspendedAsk the customer to contact the owner
LICENSE_REVOKEDLicense revokedLock paid features
DEVICE_HELDDevice heldOffer release or retry later
SEAT_PAUSEDSeat pausedSuggest buying a seat or removing a member
RATE_LIMITEDRate limitedRetry with exponential backoff
When does it need the network? When the token’s exp passes, entitlements change, a revocation must be observed, or a new device activates. The rest of the time, offline verification is enough.