DEV Community

The Honest Ceiling of Offline License Verification

Context

Originally published on lockmargin.com.

Last weekend I asked myself an uncomfortable question: could someone post my app and a valid license key on a torrent, and anyone use it for free? The answer is yes. That question sat with me all weekend. I couldn't build anything else until I mapped it, so this is the map.

Context: I'm building LockMargin, a local-first invoicing app for freelancers. $49 once. No account. No telemetry. No phone-home of any kind. The license is a signed token the app verifies locally.

The Threat Model

First, I narrowed the problem. I'm not trying to stop professional cracking crews or commercial resellers. I'm trying to survive the casual kind: a key shared in a chat, an installer plus key on a torrent, "send me your key" between friends.

Then I drew a hard line. If a mechanism breaks on a new laptop, a wiped disk, a VM - it's out. If it needs a server - out. If it needs an account - out. The app has to keep working even if my company disappears. Every option on my list had to pass that test.

The Honest Ceiling

Here is the fact most DRM marketing hides: if an application can locally answer "this token is valid," then anyone holding the same token gets the same answer. Copying the authorization is always possible when verification is local. That is not an implementation flaw. It is the architecture.

Two different things get conflated here:

  • Authenticity: did I publish this binary? Code signing answers that.
  • Authorization: does this person own a license? A signed local token answers that.

Neither prevents a buyer from handing a valid token to somebody else.

And two different threats:

  • Sharing is when a buyer gives their key to another person - the contractual and social layers help with that.
  • Cloning is when the installer and a valid key travel together.

That is where the hard limit appears: if a real installer plus a real key spreads, an offline application cannot tell the new user from the owner. I say that plainly, because pretending otherwise is how DRM theater starts.

Four Layers of Friction

Cryptographic

Each purchase gets its own signed key. There is no master key. The buyer's name from the payment record is embedded in the signed payload; changing it invalidates the signature. The email stays optional metadata, because the app never requires it.

The key is scoped to the major version: a v1 key opens v1.x forever and simply doesn't grant v2. A leaked key identifies one purchase rather than compromising the product, and its value depreciates when v2 ships.

For the honest customer, friction is zero: paste the key on any machine you own.

Contractual

The license says one person, the machines they own and control. A desktop and a laptop are fine. Passing the key around is not. A contract, not a checkpoint. The application doesn't need to phone home to enforce it.

Economic

The free tier removes the biggest reason people pirate small software: "I just want to try it." Start is free to try - up to 5 clients, 5 projects a month, unlimited invoices. No account, no card, same encryption, same offline database.

And the paid version is $49 once. For a freelancer billing $50 an hour, fifteen minutes hunting for a crack already costs more than the software.

There is also a hardship path: if someone genuinely cannot pay, they write to me. That's a personal decision, not a policy.

Social

The app shows "Licensed to: your name" in Help. Passing an abstract key is easy; passing a key with your own name signed into it is a different social operation. And transparency works as soft enforcement: the people who care about the no-DRM promise are probably not the people I'm trying to stop in the first place.

The Snake Oil I Refused

Hardware binding was on my first shortlist. Then I pictured the support email: "I wiped my disk and now your app thinks I'm a pirate." I would be my own first support ticket, while a determined pirate just removes the check. I killed it that afternoon.

An offline lease - "the key remains valid for 90 days offline" - would effectively turn my perpetual license into a subscription, and it still clones with the disk.

An activation counter without a server is a local variable. Whoever clones the state clones the count. Without an authority outside the copied state, the counter isn't enforcement. It's theater.

Obfuscation and anti-tamper raise the cost of cracking for hours and add antivirus false positives and VM problems for years. For a solo developer, the support bill exceeds the benefit.

Every one of these buys a little piracy resistance and charges it to the honest user. Some of them are reasonable choices for other products. For my constraints, all four failed.

What I Took from the Products I Studied

Sublime Text gave me the closest precedent: a per-user license entered offline, no connectivity prerequisite, an honor system that has survived for years.

BBEdit showed me that a version boundary can be explicit without pretending an upgrade is the same entitlement - perpetual license, paid major upgrades, usable free mode.

Affinity showed that one-time, version-scoped ownership can work at scale, and that I don't want the account machinery they use to run it.

Plasticity is my opposite example: once you introduce seat management, you're back to managing activation state - the thing ownership promises to abolish.

None of them satisfies all five of my constraints. That's fine. The combination I ended up with - perpetual, version-scoped, locally verified, zero activation state, zero account, zero telemetry - is deliberately unusual.

The Calculation I Kept Coming Back To

One conclusion: if I make piracy harder by adding friction, my honest customers are the ones who pay for it. Piracy exists; I'm not pretending otherwise. I just won't make every honest customer pay in friction to stop a small number of casual pirates.

The Stack I Shipped

  • Unique per-order signed tokens with the buyer's name and the major version in the payload, verified locally.
  • A license that reads like a contract.
  • The free Start tier as the legal alternative to a leaked key.
  • "Licensed to: your name" in Help.
  • No activation server, no revocation server, no telemetry.

Five layers - and after that weekend, no sixth.

I'll admit I kept looking for one more technical trick, some way to make a copied key less useful without a server. I spent more time on that search than I probably should have. There wasn't one.

And one principle above the stack: a valid license should never depend on the continued existence of the company that issued it. Servers vanish, founders vanish; the copy you bought keeps working. That's not a feature - that's the product.

If you ship offline software, where do you draw the line between protection and punishment - and what did I miss? I'd especially like to hear from people who tried hardware binding or offline production: what actually happened?

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.