Skip to Content
TauriInstallation and setup

Installation and setup of the Tauri SDK

Install

Add the crate to your Rust app, in src-tauri:

cargo add tauri-plugin-licensemanager

And the JavaScript bindings to your frontend:

npm install @licenseman/tauri

@tauri-apps/api 2 is a peer dependency, already in every Tauri app. Keep both packages on the same version: they’re released together.

Register the plugin

Copy your product’s id and public key

Open Security in the sidebar: copy the public key, and the id of the product, like x7Kp2QaZ.

Add the plugin to your app

src-tauri/src/lib.rs
const PRODUCT_ID: &str = "x7Kp2QaZ"; const PUBLIC_KEY: &str = "-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEA… -----END PUBLIC KEY-----"; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .plugin(tauri_plugin_licensemanager::Builder::new(PRODUCT_ID, PUBLIC_KEY).build()) .run(tauri::generate_context!()) .expect("error while running tauri application"); }

The plugin creates one LicenseManager for your app, and disposes it when the app exits. Reach it from Rust with app.license().

Allow it in your capability

Your windows can only call the plugin when a capability allows it:

src-tauri/capabilities/default.json
{ "identifier": "default", "windows": ["main"], "permissions": ["core:default", "licensemanager:default"] }

licensemanager:default allows everything an activation screen and locked screens need, but not the full key or the fingerprint. See frontend and permissions.

Hard-code the public key and the product id in your source code. Never load them from a file next to your app, or fetch them at runtime: whoever replaces the public key can sign their own tokens, and your app would trust them. That’s why the plugin has no tauri.conf.json configuration. See the public key.

What happens on setup

The plugin’s setup runs while Tauri starts your app, and returns right away. Then, in the background:

  1. It reads the stored key. No key: the state becomes MISSING_KEY during setup, and ready() resolves with it.
  2. With a key and a valid stored token, the state becomes ACTIVE, and ready() resolves with it right away. The online validation runs in the background: when it refuses the license, the state changes, and an event reaches your windows.
  3. With a key but no valid stored token, it validates the key online, retrying for up to 30 seconds, and ready() resolves once it’s done, with ACTIVE or the reason the app is locked.
  4. It starts the clock check, now and every hour.

The setup fails, and your app with it, only when the product id is empty, the public key isn’t a valid Ed25519 public key, or the app runs on iOS or Android. You’ll see it the first time you run the app. Everything else, a missing keychain, no network, an unreadable machine id, is handled without failing.

Your windows load after the setup, so they may miss the first changes. Render them with watchLicense, which reads the current license and then follows every change, instead of only listening to changes.

Options

Most of the time, you only need the product id and the public key. The other options have defaults that fit most apps.

use std::time::Duration; use tauri_plugin_licensemanager::{Builder, MachineFingerprint}; Builder::new(PRODUCT_ID, PUBLIC_KEY) // both required .version("2.3.1") // default: the app's version .machine_name("Jane's MacBook") // default: the hostname .platform("macOS") // default: macOS, Windows or Linux .fingerprint(MachineFingerprint::from_sync_fn(read_my_id)) // default: the system's machine id .min_offline_duration(Duration::from_secs(3 * 86_400)) // default: zero .build()
OptionDefaultWhat it does
product_idRequiredThe id of your product. Checked in every token’s aud, and used to keep each product’s stored data apart. Shown on the Security page.
public_keyRequiredYour organization’s Ed25519 public key, as the PEM shown on the Security page. Verifies every token.
versionThe app’s versionThe version of your app, sent with every validation and checked offline against the token’s mv.
machine_nameThe hostnameThe name of the machine, shown to you and in the customer portal.
platformmacOS, Windows or LinuxThe machine’s platform.
fingerprintThe system’s machine idThe machine part of the fingerprint: a string, or a function. See machine fingerprint.
min_offline_durationZeroHow long, at least, your app must keep working offline after a renewal. Makes renewals happen earlier. See renewal.
api_base_urlhttps://api.licensemanager.devFor tests only: another API origin. Trailing slashes are removed.

version

By default, it’s your app’s version from tauri.conf.json, or from src-tauri/Cargo.toml when tauri.conf.json has none: the same in development and in release builds.

machine_name and platform

Both are sent with every validation, and replace what LicenseManager knows about the machine. The hostname often holds the customer’s name, like Janes-MacBook-Pro.local, which is what makes machines easy to recognize in the customer portal. Pass your own value if you’d rather not send it.

One plugin per app

The plugin manages one product. An app selling several products, like an app and a paid plugin with their own licenses, can’t register the plugin twice: write to us if you need it.

Development and release builds

Point your development builds at a test product, and your release builds at the live one. Both share the same public key, which is one per organization:

src-tauri/src/lib.rs
const PRODUCT_ID: &str = if cfg!(debug_assertions) { "t3Hw9LmB" } else { "x7Kp2QaZ" };

A test key validated against the live product answers not_found, and the opposite too: the SDK shows INVALID_KEY.

Since both products share the public key, the product id is what stops a test key from unlocking your release build: the SDK checks it in every token. Make sure release builds can’t end up with the test product’s id, like from an environment variable a customer could set.

Packaging

There’s nothing to do. The keychain access is compiled into the plugin, for each system, with no native module to unpack and no system package to install: on Linux, D-Bus is built in.

To check it works, activate a key in your release build, then look for items of the service dev.licensemanager.sdk in the Keychain Access app on macOS, or the Credential Manager on Windows.

On macOS, each development build is signed differently, so the Keychain may ask for permission when a new build reads an entry written by a previous one. Allow it, or use a test product. Release builds signed with the same certificate don’t ask.

Network access

The SDK makes two kinds of requests, from Rust, not from your webview:

RequestWhenTimeout
POST https://api.licensemanager.dev/v1/products/{productId}/validate-keyEach validation10 seconds
HEAD https://google.com, to read the time from its Date headerOn launch, then every hour, for the clock check5 seconds

They don’t go through your webview’s Content Security Policy, or need the http plugin. On a network that blocks them, the SDK handles it like being offline.