Licensing · Fundamentals
Offline License Validation
How an app verifies a paid license with no network call — using a signed lease, a bundled public key, and a periodic online re-check.
Start FreeUpdated March 2026
Offline license validation is the difference between a desktop app that always launches and one that fails the moment a user steps onto a plane. It is also one of the most misunderstood parts of building a paid app — developers often assume validating a license requires a server call, when the better designs avoid that call entirely.
This guide explains what offline license validation is, why it matters specifically for desktop software, how the cryptography works, and how revocation is still handled when the validation itself never touches the network.
What offline license validation means
Validating a license means answering one question: is this copy of the app entitled to run its paid features? There are two ways to answer it.
The first is online validation: the app sends the license to a server, the server looks it up in a database, and it returns yes or no. The answer is always current, but the app cannot function when the server is unreachable.
The second is offline validation: the app answers the question itself, locally, with no network request. This is possible because the license is not an opaque string that only a database can interpret — it is a signed lease, a small structured document carrying its own proof of authenticity.
A signed lease contains the entitlement (who owns it, what product and plan, expiry, feature access) plus a cryptographic signature. The signature is produced on a server using a secret private key. The app ships with the matching public key. Verifying the signature with the public key proves the lease was minted by the real server and has not been altered — and that check is pure computation. No socket, no latency, no dependency on anyone’s uptime.
That is offline license validation: the app trusts mathematics it can run itself, instead of trusting an answer it has to go and fetch.
Why it matters for desktop apps
Web apps are always online by definition — validating against a server costs nothing extra. Desktop apps are different, and the expectations are different.
A macOS or Windows user launches your app on a plane, in a hotel with a captive portal, on a train through a tunnel, inside a corporate network that blocks outbound traffic on unfamiliar ports, or simply when their home internet is down. In every one of those moments, an app that can only validate its license through a server call has no good option. Fail closed, and it hangs or refuses to start for a customer who paid. Fail open, and it runs without ever confirming anything — so the check enforces nothing and can be skipped by blocking the network. The app cannot verify the license itself, and that is the real problem.
Offline validation removes that failure mode completely. The license check is local, so it succeeds in milliseconds regardless of network conditions. Launch is instant and deterministic.
There is a second benefit that accrues to you, the developer: your licensing server stops being a single point of failure. If it goes down for an hour during a deploy or an outage, not one customer is affected, because no customer’s app was depending on it to launch. A licensing system that an app must reach on every launch is fragile in a way that an offline-first system simply is not.
How the cryptography works
The mechanism is asymmetric (public-key) cryptography. The standard modern choice is Ed25519: signatures are a compact 64 bytes, verification is extremely fast, and the security properties are well reviewed.
The flow has three stages.
Signing. When a customer pays, the licensing server assembles the entitlement payload and signs it with its Ed25519 private key. The private key never leaves the server. The signed result is the lease.
Shipping the public key. The matching public key is embedded in your app binary. Public keys are safe to distribute — knowing the public key tells an attacker nothing useful. They cannot derive the private key from it, and they cannot forge a signature without the private key.
Verifying. When the app holds a lease, it parses the payload, then runs the Ed25519 verification function over the payload bytes and the signature using the public key. The function returns true or false. If true, the lease is authentic and untampered; the app then checks the plain fields — expiresAt and revoked — and decides whether to unlock.
A typical signed lease looks like this:
{
"id": "lk_01hx9z4bqncktjvx6a2r3p8wy",
"productId": "prod_myapp_pro",
"plan": "pro",
"issuedAt": "2026-05-15T09:12:00Z",
"expiresAt": null,
"revoked": false,
"sig": "base64url(ed25519_signature)"
}
The signature covers every field above sig. Change plan from pro to enterprise, or flip revoked to false, and the signature no longer matches the payload. The verification call returns false and the app rejects the lease. Tampering is not just discouraged — it is detected with certainty.
Revocation without a constant connection
The obvious objection to offline validation is revocation. If the app never asks the server, how does a refunded customer’s license ever stop working?
The answer is that offline-first does not mean offline-only. A well-designed licensing system pairs local validation with periodic online revalidation.
The app validates locally on every launch — that is the fast, always-works path. Separately, on a schedule (commonly every few days), when the app launches with a working connection, it makes one background revalidation call. That call confirms the lease is still valid server-side and picks up anything that changed: a revocation after a refund, a chargeback, an entitlement upgrade.
If the revalidation call finds the lease revoked, the app transitions to an unlicensed state. If the app simply cannot reach the server within the revalidation window, it keeps running on the last known-good lease — an outage on your side never locks a paying customer out.
The tradeoff is explicit: revocation is not instantaneous. A refunded customer who stays offline keeps a working app until their next online revalidation. In practice almost everyone reconnects within hours, so revocation propagates within days at worst. For the vast majority of apps that is entirely acceptable — and far better than the alternative, where every honest customer pays an availability tax to make dishonest ones lock out a few hours sooner.
Implementing it without writing the crypto
You can implement all of this yourself: generate an Ed25519 keypair, write a signing service, manage the private key securely, design the lease format, write the verification code for your app, build the revalidation scheduler, and handle the cached-lease fallback logic. It is a few hundred lines plus the operational burden of key management.
Or you can use a licensing layer that provides it. Keylight issues every license as an Ed25519-signed lease. Keylight holds the private key; your app ships with the public key. The Swift SDK does the local verification, the cached-lease fallback, and the periodic revalidation for you:
import KeylightSDK
// Created once at startup
let licensing = try! Keylight.manager(
sdkKey: "sdk_live_...",
tenantId: "acme",
productId: "myapp",
keyPrefix: "ACME",
trustedPublicKeyBase64: "<your-public-key>",
trialDurationDays: 14,
branding: .init(appName: "My App", purchaseURL: URL(string: "https://acme.example.com/buy")!, supportEmail: "[email protected]", tintColor: .blue)
)
// At launch — verifies the cached lease locally, then revalidates online if due
await licensing.checkOnLaunch()
switch licensing.state {
case .licensed:
enablePaidFeatures()
case .trial(let daysLeft):
showTrialBanner(daysLeft: daysLeft)
case .expired:
showRenewalPrompt()
case .invalid:
showActivationSheet()
}
checkOnLaunch() runs the local signature verification first, so the app is licensed and usable instantly. Revalidation happens in the background when a connection is available and the revalidation window has elapsed. The customer never waits on the network; you never write the cryptography.
For the broader picture of how keys are generated, delivered, and revoked, see Software License Keys Explained. For how device activation is counted and enforced across a customer’s devices, see the app activation system guide. When you are ready to wire it to your own Stripe account, Pricing lists the plans — starting at $19/month.
Frequently asked
What is offline license validation?+
Offline license validation is when an app verifies a license without contacting a server. The license is cryptographically signed; the app checks the signature locally using a public key it ships with.
How does an app validate a license without internet?+
The license is a signed lease. The app holds the matching public key and verifies the signature in memory — no network request. If the signature and entitlement fields are valid, the license is accepted.
How is a revoked license caught if validation is offline?+
The app revalidates online periodically — typically every few days. A license revoked after a refund is rejected on the next online re-check, not instantly, which is the deliberate tradeoff for offline support.
Start licensing your app today
Drop in the Swift SDK, point it at your dashboard, and sell paid apps in under a minute. Free forever tier included.
Start Free