Skip to main content
Migrate Already selling? Move your customers to Keylight without re-issuing a single key.
Keylight
Blog
cross-platform architecture license-keys

Licensing a Cross-Platform App from One Control Plane

4 min read Nicolas Demanez — Founder

If you ship the same product on more than one platform — a native Mac build, an Electron or Tauri desktop app, a Rust CLI — the licensing question is not “how do I license each one?” It is “how do I license all of them without running three disconnected systems?” The answer is a single control plane: one tenant that owns your customers, keys, and device limits, with thin SDKs in each app that all read the same signed lease. This post is the build guide for that setup.

What “one control plane” means

A control plane is the place the licensing truth lives. With Keylight it is your tenant: one account that holds every customer record, every license key, the activation count and limit on each key, the entitlements each key grants, and the Stripe connection that mints keys on purchase. The dashboard, the revocation controls, the activation resets — all of it operates on that one set of records.

The SDKs are deliberately not the control plane. They are clients. Each one does the same three things in its own language: exchange a key for a signed lease, verify that lease locally, and read entitlements from it. None of them holds authority over whether a license is valid — they verify a document the control plane signed. That separation is the whole point. It means a customer who buys once exists once, and a device limit of three means three devices total, not three per platform.

This is the universal licensing layer idea made concrete: licensing is infrastructure you configure once, not a backend you rebuild per app.

One lease format, every SDK

What makes a single control plane work across languages is that the lease format is shared. A Keylight lease is an Ed25519-signed document with a fixed wire format. Signing happens once, server-side; every SDK reconstructs and verifies that same format against the tenant’s public keys. The Swift SDK and the Rust crate are not two implementations of “a license” — they are two readers of one signed artifact.

The practical consequence: the SDKs are at parity by construction. The same license states exist everywhere — Licensed, Trial, Limited, FreeTier, Expired, Invalid — because they are derived from the same lease fields. hasEntitlement("pro") means the identical thing in Swift, JavaScript, and Rust, because all three are checking the same signed entitlements field. For the field-by-field anatomy of that shared document, see what is inside a Keylight lease.

Wiring every SDK to one tenant

Here is the same product, configured against one tenant in each of Keylight’s SDKs. Notice that the tenantId and productId are identical in every one — that is what binds them to the same control plane.

The native Mac build, in Swift, via the Keylight.manager factory:

let licensing = try Keylight.manager(
    sdkKey: "sdk_live_…",
    tenantId: "your-tenant",
    productId: "your-product",
    keyPrefix: "PROD",
    trustedPublicKeyBase64: "<tenant public key>",
    trialDurationDays: 14,
    branding: .init(
        appName: "My App",
        purchaseURL: URL(string: "https://example.com/buy")!,
        supportEmail: "[email protected]",
        tintColor: .accentColor
    )
)

A Tauri desktop build, registered in the Rust core:

use keylight::KeylightConfig;

let cfg = KeylightConfig::builder("your-tenant", "your-product", "sdk_live_…").build();
tauri::Builder::default()
    .plugin(tauri_plugin_keylight::init(cfg));

A Rust CLI or a non-Tauri Rust app, using the crate directly:

use keylight::{Keylight, KeylightConfig};

let cfg = KeylightConfig::builder("your-tenant", "your-product", "sdk_live_…").build();
let kl = Keylight::new(cfg)?;
let res = kl.activate("USER-LICENSE-KEY")?;

And an Electron build, with the JavaScript SDK in the main process:

const kl = new Keylight({
  tenantId: "your-tenant",
  productId: "your-product",
});

Four apps, one tenant. A customer’s key activates on their Mac app and their CLI, and both activations count against the same limit. Revoke that key once in the dashboard and every app rejects it on the next revalidation. There are per-platform integration walkthroughs in how to add license keys to a Swift macOS app, an Electron app, and a Tauri app.

Where this lands today, honestly

The control plane is real and shared, but it is worth being precise about what “cross-platform” covers right now rather than overselling it. The shipped SDKs are Swift (Apple platforms), JavaScript/TypeScript (web, Node, Electron, edge), Rust, and the first-party Tauri plugin. Those cover the bulk of where independent desktop and AI-native apps ship today.

What this is not, yet, is a drop-in REST API you can call from any language that lacks a native SDK. Additional language SDKs are added based on real demand, not to fill a matrix. The design makes that cheap: because the lease format and the control plane are shared, a new SDK is another reader of the same document, not a new system. So the honest framing is “one control plane across the SDKs that exist” — which is most of the market — rather than “licenses any language anywhere.” When you only ship on platforms with a Keylight SDK, the single-tenant model already holds end to end.


A cross-platform app does not need cross-platform licensing complexity. It needs one place the licensing truth lives and thin, identical clients in each app reading the same signed lease. Configure the tenant once, point each SDK at it, and the platform count stops being a licensing problem. If you are wiring up a stack this post does not cover, send us your feedback and we’ll help.

Frequently asked

Can one license system cover apps written in different languages?+

Yes. Keylight issues the same Ed25519-signed lease format regardless of which SDK reads it. The Swift, JavaScript, Rust, and Tauri SDKs all verify that one format, so a single tenant covers a Mac app, an Electron app, and a Rust CLI at once.

Do customers and device limits carry across platforms?+

Yes — they live on the tenant, not in the SDK. A customer, their key, its activation count, and its entitlements are one record. Whichever SDK activates a device increments the same count against the same limit.

Which platforms does Keylight cover today?+

Shipped SDKs are Swift (Apple), JavaScript/TypeScript (web, Node, Electron), Rust, and a first-party Tauri plugin. More language SDKs are added based on demand; the lease format and control plane are shared, so new SDKs slot into the same tenant.

Ready to ship?

Create your account and start licensing your apps in under a minute. Free forever tier included.

Start Free