Tauri Plugin keygen
This plugin helps you implement timed licensing (with trial) and feature-base licensing for your Tauri desktop app using the Keygen Licensing API.
It handles license validation requests, verifies response signatures, caches valid responses, and manages the machine file for offline licensing.
Licensed state is managed in the Tauri App State (Rust back-end), and can be accessed via JavaSript Guest bindings in the front-end.
📖 Table of Contents
:tv: Video Tutorial
:arrow_down: Install
This plugin is made for Tauri v1. But, it'll be updated on Tauri v2 stable release.
🦀 Add the following line to src-tauri/cargo.toml
to install the core plugin:
[]
= { = "https://github.com/bagindo/tauri-plugin-keygen", = "main" }
👾 Install the JavaScript Guest bindings:
:electric_plug: Setup
First, sign-up for a free account and get your Keygen Account ID and Keygen Verify Key.
Then, add them to the plugin builder in src-tauri/src/main.rs
:gear: Custom Configs
Optionally, you can specify custom configs to the plugin builder.
:globe_with_meridians: with_custom_domain
You don't need to specify your Keygen Account ID if you're using Keygen Custom Domain.
[!NOTE] Chaining the
api_url
config won't matter here.
:zap: Usage
:stopwatch: Timed License - with trial
In this example, the app's main page is guarded by a layout route _licensed.tsx
, that will re-direct users to the validation page if they don't have a valid license.
Watch the video tutorial for the step-by-step implementation.
The main code snippets:
_licensed.tsx
// Tauri
import from "tauri-plugin-keygen-api";
// React
import from "@tanstack/react-router";
export const Route = ;
validate.tsx
// Tauri
import
:medal_military: Feature Base License
In this example, users can access the app without having a license, except when they want to add an image to an ESP item.
Watch the video tutorial for the step-by-step implementation.
The main code snippets:
esp.tsx
// Tauri
import from "tauri-plugin-keygen-api";
// React
...
import from "jotai";
// App
import from "../atoms";
import ProLicenseModal from "../components/ProLicenseModal";
// Main Page
ProLicenseModal.tsx
// Tauri
import from "@tauri-apps/api/shell";
// React
import * as Dialog from "@radix-ui/react-dialog";
import from "@tanstack/react-router";
import from "jotai";
// App
import from "../atoms";
export default
validate.tsx
// Tauri
import
:space_invader: JavaScript Guest Bindings
Available JavaScript APIs:
:ticket: getLicense()
Get the current license from the LicensedState
in the Tauri App State.
Returns KeygenLicense
or null
.
import from "tauri-plugin-keygen-api";
const =>
How does this plugin manages LicensedState
?
🔍 On App Loads: Look for offline license
When your Tauri app loads, this plugin will look for any offline licenses in the [APP_DATA]/keygen/
directory.
If a machine file (📄 machine.lic
) is found, it will verify and decrypt the machine file, parse it into a License
object, and load it into the Tauri App State.
If there's no machine file, it'll look for the cache in 📂 validation_cache
, verify its signature, parse the cache into a License
object, and load it into the Tauri App State.
🚫 No valid license
If no offline license is found, or if any of the offline license found is invalid due to any of the following reasons:
- Failed to decrypt the machine file
- The machine file
ttl
has expired - Failed to verify the response cache signature
- The cache's age has exceed the allowed
cache_lifetime
- The parsed license object has expired
the LicensedState
in the Tauri App State will be set to None
(serialized to null
in the front-end).
🔄 State Update
You can't update the LicensedState
directly.
Aside than initiating the state from the offline licenses on app loads, this plugin will update the licensed state with the verified response from validateKey()
or validateCheckoutKey()
, and reset it back to None
when you call resetLicense()
.
:old_key: getLicenseKey()
Get the cached license key.
Returns string
or null
.
The license key is cached separately from the offline licenses, so that when the offline licenses expired and getLicense()
returns null
, you can re-validate without asking the user to re-enter their key.
import from "tauri-plugin-keygen-api";
const =>
[!TIP] Instead of re-directing to the
validate
page, you can re-validate the cachedlicenseKey
in the background. Checkout the video tutorial to see how you can do this.
:rocket: validateKey()
Send license validation and machine activation requests.
Params | Type | Required | Default | Description |
---|---|---|---|---|
key | string |
✅ | - | The license key to be validated |
entitlements | string[] |
[] |
The list of entitlement code to be validated | |
cacheValidResponse | boolean |
true |
Whether or not to cache valid response |
Returns KeygenLicense
. Throws KeygenError
.
import
What happens under the hood when you call validateKey()
?
🆔 Parsing Machine Fingerprint
This plugin parses the user's machine fingerprint
and includes it in both license validation and machine activation requests.
[!TIP] You can utilize machine fingerprints to prevent users from using multiple trial licenses (instead of buying one). To do this, set the
machineUniquenessStrategy
attribute toUNIQUE_PER_POLICY
on your trial policy.See the video tutorial for more details.
🔏 Verifying Response Signature
A bad actor could redirect requests to a local licensing server under their control, which, by default, sends "valid" responses. This is known as a spoofing attack.
To ensure that the response received actually originates from Keygen's servers and has not been altered, this plugin checks the response's signature and verifies it using the Verify Key you provided in the plugin builder.
A bad actor could also "record" web traffic between Keygen and your desktop app, then "replay" valid responses. For example, they might replay responses that occurred before their trial license expired, in an attempt to use your software with an expired license. This is known as a replay attack.
To prevent that, this plugin will reject any response that's older than 5 minutes, even if the signature is valid.
🔄 Updating State and Cache
Once the response is verified, this plugin will update the LicensedState
in the Tauri App State with a License
object parsed from the response.
If the License
is valid and cacheValidResponse
is true, the verified response will be cached for later use as an offline license.
:rocket: :computer: validateCheckoutKey()
Call validateKey()
, then download the machine file for offline licensing.
Returns KeygenLicense
. Throws KeygenError
.
import
As with validateKey()
, it will also parse the machine fingerprint, verify the response signature, and update the Tauri App State.
The only different is that when it received a valid license, instead of caching the response, this plugin will download the machine.lic
file for offline licensing.
🔃 resetLicense()
Delete all the offline licenses (validation cache and machine file) in [APP_DATA/keygen/]
and set the LicensedState
in the Tauri App State to None
.
🔃 resetLicenseKey()
Delete the cached license key on [APP_DATA]/keygen/
.