All posts
Tutorial Desktop

Software Licensing for Desktop Applications

PC
PermitCore
September 16, 2026 · 6 min read

A SaaS product can gate access at the server — no server call, no access. A desktop app runs on hardware you don't control, which means licensing has to answer a harder question: how do you enforce anything on a machine the user fully owns? Here's what actually matters, independent of language or platform.

Node-locking: binding a license to one machine

The core primitive for desktop licensing is tying a license to a specific device via a hardware fingerprint generated on first run and sent along with every activation. Done well, this doesn't mean picking one fragile signal (a MAC address is a famously bad choice — see why) but combining several stable, non-network-dependent values into one hash. The server then enforces an activation limit — typically 1-3 devices per license — independent of how the fingerprint itself is computed.

Trial periods, done honestly

A time-limited trial for desktop software needs to resist the obvious bypass: uninstall, reinstall, get a fresh trial forever. A trial tied only to a local install date is trivially defeated this way. A more resistant approach ties trial eligibility to something that survives a clean reinstall — a server-side record keyed to a payment-method fingerprint (for a paid-trial model) or an account, not just local install state. PermitCore's own free-trial system uses exactly this shape: server-side eligibility tracking with card-fingerprint anti-abuse checks, not a local timer the app can't actually defend.

Surviving reinstalls and OS reinstalls

A device fingerprint built entirely from OS-level identifiers can change across a full OS reinstall, breaking node-locking for a legitimate customer who did nothing wrong. The practical answer is a reactivation path: if the same license key activates again from what's recognizably the same device (or simply within its activation limit), let it succeed rather than treating every fingerprint change as a new device consuming a new seat — and give the customer a self-service way to deactivate an old device themselves rather than requiring a support ticket every time they get a new machine.

Working without a constant connection

Unlike a web app, a desktop app can't assume the network is always there. The practical baseline is graceful degradation: if a validation call fails purely because the server is unreachable, fall back to the last known-good result rather than blocking the user outright — PermitCore's SDKs do exactly this automatically on every validate()/activate() call, no separate "offline mode" required. For apps that need to run disconnected for longer stretches by design (not just tolerate a flaky connection), a deliberately signed offline token is the stronger mechanism — see our offline validation deep dive for how that works and what it can't protect against.

What this doesn't solve

None of the above stops a sufficiently motivated user from reverse-engineering a binary and patching out the license check entirely — no licensing system, desktop or otherwise, fully prevents that. The realistic goal is raising the bar past "trivial to bypass," combined with server-side abuse detection for the much more common case: a legitimately-obtained key shared more widely than intended.

Previous: How to Build a License Key System Next: What Happens If a License Server Goes Down?