Node.js SDK
This guide will get you all set up with our Node.js SDK to integrate the licensing part of Moonbase into your node-based apps.
Using this SDK is great if you are building Electron apps or other app running on devices directly. It is not suitable for web-apps, since we need to fingerprint the underlying device, and we are currently relying on system information to do that.
Check out our simple Electron sample app for an example of how this integration can work:
Sample Electron app that integrates Moonbase for licensing
Getting started
Start by adding the npm package to your project:
npm install @moonbase.sh/licensing --save
If you haven't already, create a product in the Moonbase app, and check out the Implementation guide to get the relevant cryptography keys, endpoints and configuration. An example configuration could look like this:
import { FileLicenseStore, MoonbaseLicensing } from "@moonbase.sh/licensing"
const licensing = new MoonbaseLicensing({
productId: 'demo-app',
endpoint: 'https://demo.moonbase.sh',
publicKey: `-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAutOqeUiPMgYjAwQ53CyKhJSqojr2bejce0CshQi9Hd8mNZbkoROx
oS56eIzehFSlX4YwHnF47AR1+fPOe7Q33Cgzd6d9xqksiMH7sWK2mADIlB66vZdW
uk3Me0UMB22Biy1RQbSRMivu79MxCofsympoL/5CFjJLd1u37kxjuRWVLjJS84Rr
3L2W7R7Exnno/giC+L/Dv711mjgstmtlAQm5ZINvFvoLA1eFTDs6nlCs3dpJSiq3
fsBUMT9FtudzS5As54jeT/8MB66fJJ0A1LQ/v5CW8ACQYseFSIoOKErD3xU7QLIJ
ERUn++6CVMPvZo67jVbTY+GCXYfW4gGVZQIDAQAB
-----END RSA PUBLIC KEY-----`,
// Optionally adjust the license store with path
// to where the license should be stored, or use
// alternate storage mechanisms to persist the token.
licenseStore: new FileLicenseStore(),
})
This snippet sets up an instance of the licensing client where you will find all the features described below.
The licensing
instance will come with four main features:
ILicenseStore
that handles license token persistence, either to file or in-memoryILicenseClient
which is a HTTP client built around the Moonbase licensing APIILicenseValidator
that can validate license tokens with the given public keyIDeviceIdResolver
which by default generates unique device fingerprints using a number of factors
Like described in activation flows, multiple activation flows are possible through Moonbase, and the Node.js SDK currently supports browser based activations and offline activations only. Let's take a look at how each would be implemented using the SDK.
Browser based activations
Using browser based activation is the recommended flow, and the easiest to get going with. To start, request an activation using the SDK:
const activationRequest = await licensing.client.requestActivation()
This activationRequest
contains a browser
URL that the customer can use to fulfill the request, so let's open a browser:
import open from 'open'
open(activationRequest.browser)
While the customer is activating the license or requesting a trial, we can poll for completion:
let license: License | null = null
do {
await new Promise((resolve) => setTimeout(() => resolve(void 0), 5000))
license = await licensing.client.getRequestedActivation(activationRequest)
} while (license == null)
As soon as the customer has fulfilled the request, a License
will be ready for us.
The Moonbase SDK will ensure any License
coming through the API client contains a valid signature, and matches the current device automatically.
Keep in mind that this license activation might be a full license, or a time-scoped trial.
To make sure the customer doesn't have to keep doing this, it's best to persist the license to disk:
await licensing.store.storeLocalLicense(license)
That way you can easily add a check when your app starts, to see if you can skip product activation entirely:
const localLicense = await licensing.store.loadLocalLicense();
const validatedLicense = await licensing.client.validateLicense(localLicense);
// License has been re-validated, store updated license for next check
await licensing.store.storeLocalLicense(validatedLicense);
Our Electron app sample has a more complete startup guard that might be helpful: withLicensing
Offline activations
You might have customers that need to be able to activate devices without connection to the internet. To facilitate this, Moonbase signs all license tokens we issue with the unique signature of the device being activated. Since offline devices cannot transmit this device signature over the internet, the app needs to generate a device token. This device token contains the necessary information to generate a valid license token for offline activations, and can easily be exchanged for a license by the customer in the customer portal.
To start, generate a device token:
import fs from 'node:fs/promises';
import path from 'node:path';
const bytes = await licensing.generateDeviceToken()
const tokenPath = path.join(path.resolve(), 'device.dt')
await fs.writeFile(tokenPath, bytes)
The snippet above generates the token, and then writes the result to a device.dt
file.
You can change the file name, but keep the extension to ensure compatability with the customer portal interface.
It's up to you to provide the necessary instructions to the customer for how to upload the device token to your customer portal.
What customers receive when they upload the device token in the customer portal is a license.mb
file.
This file contains a valid offline activated license token that you can read in using the SDK:
const licenseBytes = await fs.readFile(path);
const license = await licensing.readRawLicense(licenseBytes);
// License has been read, store license for next check
await licensing.store.storeLocalLicense(validatedLicense);
Keep in mind that this license will have a ActivationMethod
of Offline
, which means trying to re-validate the license is not necessary.