Stored data
The SDK stores four small values per product, in the system keychain, and mirrors them in files in case the keychain is unavailable or loses them.
| Value | What it is | Written |
|---|---|---|
licenseKey | The key the customer activated. | When setLicenseKey() succeeds. |
licenseToken | The last license token. | At each successful validation. Deleted when LicenseManager refuses the license. |
installId | The random part of the fingerprint. | The first time the fingerprint is computed. Never changed afterwards. |
lastSeen | The latest time seen by the clock check, lightly obscured in base64. | At each clock check. |
Nothing else is stored: no customer data, no history.
The keychain
macOS
The Keychain of the user, as generic passwords.
Every entry has the service dev.licensemanager.sdk, shared by all apps using the SDK, and an account made of your product id and the value’s name, like x7Kp2QaZ:licenseKey. Two apps, or two products, never read or overwrite each other’s entries.
The keychain is reached through @napi-rs/keyring, an optional native dependency. When it isn’t installed or can’t be loaded, the SDK uses the files only, without any error. See packaging.

Files
Each value is also written to two folders, even when the keychain works:
| System | Folders |
|---|---|
| macOS | ~/Library/Application Support/.<namespace> and ~/Library/Caches/.<namespace> |
| Windows | %PROGRAMDATA%\<namespace> and %APPDATA%\<namespace> |
| Linux | ~/.config/.<namespace> and ~/.local/share/.<namespace> |
<namespace>is the first 32 hex characters of the SHA-256 ofdev.licensemanager.sdk:<productId>. It looks like a random id, and doesn’t mention licenses or your app.- Each value is in a file named after the first 24 hex characters of the SHA-256 of its name, like
3f1a…c9.dat. - Files are created readable by the user only (
600) on macOS and Linux. They aren’t encrypted. - Writing to one folder can fail without affecting the other.
On Windows, %PROGRAMDATA% is shared by every user of the computer: another user account that has no keychain entries may read the key, token and install id written there by the first user, and run activated, on the same machine.
Reading and writing
| Operation | What happens |
|---|---|
| Read | The keychain first. When it has no value, or fails, each folder in order. The first value found wins. |
| Write | The keychain, then both folders. Each one can fail on its own: the others are still written. |
| Delete | The keychain entry and both files. |
None of them ever throws: storage is best effort, and a failure never crashes your app.
Uninstalling
The stored data is kept when your app is uninstalled, on purpose: the keychain and the folders are outside your app’s folder. A customer who reinstalls your app is still activated, with the same fingerprint, and doesn’t take a new place on their license. A trial can’t be restarted by reinstalling either.
Resetting during development
To start over as a new customer, delete the entries of your product in the keychain, and the two folders: when only one of them is deleted, the SDK reads the values from the other.
Compute your product’s namespace:
node -e 'console.log(require("crypto").createHash("sha256").update("dev.licensemanager.sdk:x7Kp2QaZ").digest("hex").slice(0, 32))'macOS
for name in licenseKey licenseToken installId lastSeen; do
security delete-generic-password -s dev.licensemanager.sdk -a "x7Kp2QaZ:$name"
done
rm -rf ~/Library/Application\ Support/.<namespace> ~/Library/Caches/.<namespace>Deleting the install id changes the fingerprint: your computer becomes a new machine on the license. Use a test product, where it doesn’t matter.
For automated tests, pass storageDirs with a temporary folder: the files go there instead. The keychain is still used when it’s available.
Never tell customers to delete these files to fix a problem: they lose their activation, and their computer becomes a new machine, which can be refused with machine_limit_reached.
Edge cases
The keychain asks for permission. On macOS, a build signed with another certificate than the one that created an entry, like a development build after a release build, can make the Keychain ask the customer to allow access. When access is denied, the SDK reads the values from the files.
The keychain is locked or unavailable, like over SSH, on a headless Linux, or when the Secret Service isn’t running. The SDK uses the files.
The keychain and the files disagree, like after restoring a backup. The keychain wins when it has a value.
A read-only home folder, and no keychain. Nothing can be stored: the customer must activate on every launch, and each launch is a new machine. Very unlikely on a customer’s computer.