Node.js SDK
Drop-in source files for Node.js — copy them into your project. Nothing to install from a package registry.
Download
Two files, no dependencies (Node 18+). Copy what you need:
| File | Runs on | Purpose |
|---|---|---|
licenseClient.js | your customers' machines | checks a license |
automationClient.js | your server only | creates and manages keys with an API token |
License client
const { LicenseClient } = require('./licenseClient');
const client = new LicenseClient({
baseUrl: 'https://license.foliox.sbs',
product: 'YOUR_PRODUCT_ID', // shown on the product's page in your dashboard
publicKeyB64: 'PASTE_PUBLIC_KEY_FROM_THE_DOCS', // public - not a secret
});
const result = await client.check(licenseKey); // activates on first run, verifies afterwards
if (result.valid) {
console.log('licensed, status:', result.status, 'expires:', result.expiresAt);
} else {
console.log('not licensed:', result.reason);
}
See example.js for a runnable script. Useful extras: client.require(key) (throws LicenseInvalid), client.clearCache(), isValidKeyFormat(key), computeHwid().
What it does for you
- HTTPS only (plain
http://is refused except for localhost while developing); certificates always verified, TLS 1.2+, redirects never followed. - Nothing is believed before its Ed25519 signature is checked, then the product it names and its age (
max response age, default 15 minutes) so an old captured answer can't be replayed. - Safe retries: network errors, timeouts, HTTP 429 and 5xx are retried with exponential backoff + jitter inside a hard deadline (default 20 s). A definite answer (revoked, expired, wrong device) is never retried or softened.
- Offline grace from the last valid signed answer (72 h, never past the key's own expiry), bound to this device, product and key; the raw key is never stored; a definite "no" deletes it; a clock set back is detected.
check()never raises/panics for runtime conditions - it returns a result. Bad configuration is reported when the client is created.
Offline grace is a resilience feature, not a security boundary. See the SDKs & API wrapper page in your server's docs for the full list, what no client library can do, and upgrade notes from v1.
Automation client (server side)
const { AutomationClient } = require('./automationClient');
const api = new AutomationClient({ baseUrl: 'https://license.foliox.sbs', token: process.env.LICENSE_API_TOKEN });
const [key] = await api.createKeys('YOUR_PRODUCT_ID', { durationDays: 365, customerEmail: '[email protected]' });
console.log(key.key);
await api.revokeKey(key.key);
// a public key: no device binding, so any number of people can use the same key at once
const [shared] = await api.createKeys('YOUR_PRODUCT_ID', { keyType: 'public' });
keyType is 'device' (the default: each key locks to the first device that activates it) or 'public'. The license client above works with both types unchanged.
The token can mint keys: keep it in an environment variable or secret manager on a server you control, never in software your customers run. Every failure is a typed error (NotFoundError, PlanLimitError, RateLimitedError, ...). Creating keys is not retried after an ambiguous failure, so it can't create duplicates.