Activating Machines

Use Keygen's API and your code to implement machine activation for your product. If you need help after reading this, can reach out to us anytime at [email protected].

This tutorial is written in JavaScript, but you can follow along in any other language that you're comfortable in. Throughout this tutorial, you will see placeholders such as {ACCOUNT} within the code examples that will need to be replaced with an ID for that particular resource type.

Before getting started, you will either need to log into your Dashboard and generate a product token, or generate an authentication token via the API. To create a token directly through the API, check out the code examples in the API reference or check out our guide on authenticating users.

If you are using product tokens, the code for this tutorial should not be written client-side. If you are wanting to allow users to activate machines for themselves client-side, then you should authenticate them and use an authentication token which belongs to them; otherwise, all code should be server-side.

Your admin and product tokens carry many privileges and should always be kept secret. Do not share your secret API tokens in publicly accessible areas such GitHub, embed them in client-facing code e.g. inside of your product, and so forth. Learn more.


Once you've created a license, you can "activate" individual machines for your product to be used on, making it easier for you to implement e.g. a node-locked licensing model. Although Keygen doesn't use the term "activation" much in our resource documentation, machine creation accomplishes the same thing, while machine deletion would be "deactivation."

Activation can either be done client- or server-side, and depending on which one of those you choose, the tokens you use to make the request will be different i.e. product tokens vs. user tokens, for server-side vs. client-side machine activation, respectively.

If you're not using Keygen to manage users, all machine activations will need to be done server-side. In order to perform activation client-side, you will need to be authenticated as a user, because embedding your own authentication tokens within your app is not secure.

When activating a machine, you will at minimum need a license ID for the license the activation is for, a fingerprint for the current device, as well as an optional user ID for client-side activation. Other machine attributes, such as IP or hostname, are completely optional.

In the example below, we'll be using a SHA1 hash of the current device's MAC address as a fingerprint. We're hashing the user's MAC address as a simple way to anonymize it, since we have no real use in knowing its actual value.

Although we're using the MAC address in this example, a fingerprint can be any unique string able to be reproducibly queried from the device, e.g. you could write a secure random string to a file on disk or to a registry and use that, but for example purposes the device's MAC address works well enough.

Fingerprinting the device

const sha1 = require("sha1")
const { promisify } = require("bluebird")
const { getMac } = require("getmac")

const getMacAddress = promisify(getMac)
const getFingerprint = async () => {
  return sha1(await getMacAddress())
}

Next up, we'll use our getFingerprint function above while creating a new machine resource that is associated with the current user and their license. Before activating a machine, you should validate the current license to make sure its policy will allow for an additional machine activation.

You can utilize a policy's maxMachines, floating and concurrent attributes to enforce your desired rules for machine usage. For example, you can create a policy which allows up to 3 machines to be activated per-license by setting maxMachines=3, floating=true, and concurrent=false.

You can check how many machines a license is allowed to have through its maxMachines attribute, which is synced with the license's policy. You can also query all of a license's machines through its machines relationship. These can be useful for managing UI state, e.g. not showing an "activate machine" action if the user is already at their machine activation limit.

Activating the machine

const fetch = require("node-fetch")

const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/machines", {
  method: "POST",
  headers: {
    "Content-Type": "application/vnd.api+json",
    "Accept": "application/vnd.api+json",
    "Authorization": "Bearer {TOKEN}"
  },
  body: JSON.stringify({
    "data": {
      "type": "machines",
      "attributes": {
        "fingerprint": await getFingerprint()
      },
      "relationships": {
        "license": {
          "data": { "type": "licenses", "id": "{LICENSE}" }
        },
        "user": {
          "data": { "type": "users", "id": "{USER}" }
        }
      }
    }
  })
})

const { data: machine, errors } = await response.json()
if (errors) {
  // … handle errors
}

console.log(`Machine activated: ${machine.attributes.fingerprint}`)
Are you deploying your software to an air-gapped/offline environment? If so, check out our example client/server implementation of offline license activation for air-gapped machines using Keygen, Node.js, React, RSA crypto, QR codes, and a mobile device.

Next steps

Congrats! You've activated your first machine using Keygen. Next up, we could update a license's policy to require a machine fingerprint during validating using the requireFingerprintScope setting. If you have any questions about what you've learned today, be sure to reach out!