Validating Licenses

Use Keygen's API and your code to validate licenses 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 create licenses 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.

Validate by license key

If you would like to validate a license by key, you can use the validate-key action. Validating a license key does not require an API authentication token, unlike validating by a license ID. This action is especially useful if you aren't generating activation tokens, or using Keygen to manage user accounts, and would rather generate and validate license keys directly.

Did you know that you can require a machine fingerprint during a license validation request? This is incredibly useful when implementing licensing models which require tracking machine usage, e.g. a node-locked model or a floating license model.

The response of the validation request will be a meta object containing the result of the validation: a meta.valid boolean, and a meta.detail human-readable description of the validation result.

// … above code to request a license

const validation = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/licenses/actions/validate-key", {
  method: "POST",
  headers: {
    "Content-Type": "application/vnd.api+json",
    "Accept": "application/vnd.api+json"
  },
  body: JSON.stringify({
    "meta": {
      "key": "C1B6DE-39A6E3-DE1529-8559A0-4AF593-V3"
    }
  })
})

const { meta } = await validation.json()
if (meta.valid) {
  // … do something
} else {
  // … do something else
}

Validate by license ID

To validate a license directly by it's ID, send a POST request to the license's validate action. Validating a license by ID requires an authentication token. We recommend using an activation token, or a token which belongs to one of your users. But if you're validating licenses server-side, then using an admin or product token also works just as well.

You can provide additional information for license validations using meta.scope. This is useful for providing things such as a machine fingerprint for certain licensing models.

The response of the validation request will be a meta object containing the result of the validation: a meta.valid boolean, a meta.constant machine-readable constant, and a meta.detail human-readable description of the validation result.

// … above code

const validation = await fetch(`https://api.keygen.sh/v1/accounts/{ACCOUNT}/licenses/${license.id}/actions/validate`, {
  method: "POST",
  headers: {
    "Content-Type": "application/vnd.api+json",
    "Accept": "application/vnd.api+json",
    "Authorization": "Bearer {ACTIVATION_TOKEN}"
  },
  body: JSON.stringify({
    "meta": {
      "scope": {
        "fingerprint": await getFingerprint()
      }
    }
  })
})

const { meta } = await validation.json()
if (meta.valid) {
  // … do something
} else {
  // … do something else
}

Validate key offline

To allow offline license key validation, you can cryptographically sign or encrypt license keys, which can be verfied using your account's public key, available in your Dashboard's settings page. You can configure licenses to utilize a cryptographic scheme at the policy level through the scheme attribute.

For example, when using the RSA_2048_PKCS1_SIGN_V2 scheme, when a license is created which implements this policy, the provided key will be cryptographically signed and that signature will be appended onto the end of the key. You can then cryptographically verify the entire key in offline environments.

The resulting license key will resemble the following:

key/dGVzdA==.TrtLt-NTwwWSpAoFxewg8OoCoGNq2ifZx0gGTaresI1U8SU8vyF5HTbZKtli8WOsXeACjQBYMqxj5POPGVddEej8gfgiZULySomLbweZWJkQ_EKyKgtz0M_MN7Y7w2QWVW-ug-ES4ekOA8mLda4Ue4MYj3tEBftmMyooZPwhTQt70Mv5w-AmxPqtoZI76qI6ZZ6dV9aJGGs2ixqy3ozUkC0ZFVSgXutX2Eo2gnyPTCMCJEtTR9IymZXxaQCJo-tGWF9rvCewnn-YsMcGsD7Uz9eGLBbi-scEKFOVr_EqMm_veCR_piH3WkRaaEVXO4esevLvs7EsbksyWyFiUbN5ug==

The key contains a base64 encoded version of the key specified at the time of creation, along with a cryptographic signature, delimited by the . character. You can split the key by the . character to verify its contents using RSA's signature verification methods.

In this case, our key is an encoded JSON object which contains additional information on the license. After verification, we can parse it and use this information in our software. For example, you could specify how long the license is allowed to be offline, its offline usage limits, etc.

const crypto = require('crypto')
const {
  KEYGEN_PUBLIC_KEY,
  LICENSE_KEY
} = process.env

// Extract key and signature from the license key payload
const [signingData, encodedSignature] = LICENSE_KEY.split('.')
const [signingPrefix, encodedKey] = signingData.split('/')

// Decode the base64 encoded key
const key = Buffer.from(encodedKey, 'base64').toString()

// Verify the signature
const verifier = crypto.createVerify('sha256')
verifier.write(`key/${encodedKey}`)
verifier.end()

const ok = verifier.verify(KEYGEN_PUBLIC_KEY, encodedSignature, 'base64')
if (ok) {
  const payload = JSON.parse(key)

  console.log('License key is valid!', { payload })
} else {
  console.log('License key is invalid!')
}

The exact behavior of each scheme is detailed in our API reference.


Handling failures

Depending on your product and business requirements, you may want to implement additional logic when, for example, your user does not have an active internet connection, or their license fails validation for some reason or another. Below are a few license validation failure scenarios:

Validation request was successful, but license is not valid

License validation failures are innevitable, and how you handle them will differ based on your business requirements. Here are a few ideas for handling such a situation:

  1. Immediately show a dialog detailing the validation failure (you can find out the reason using the meta.constant key within the validation response).
  2. Depending on how you're licensing your product (e.g. user accounts with associated licenses vs. only license keys), you can prompt the user to purchase a new license, resolve the invalid license, etc.

Alternatively, you could disallow access to the product, or implement a grace period while prompting the user to resolve the validation failure—though ideally, this should be communicated beforehand by listening for upcoming license expiration and overdue check-in events (e.g. license.expiring-soon and license.check-in-required-soon) so that the potential for validation failures i.e. license churn is diminished.

Validation request failed e.g. timeout

The failure could be for a number of reasons, but the most likely culprit is that your user doesn't have an active internet connection. You could handle this in a variety of ways, but here are a few ideas:

  1. Begin a grace period (e.g. 30 days or 5 additional product usages), where you disallow access to the product if a license validation has not been successful after that timeframe. You should clearly tell your users that they should connect to the internet when possible and be upfront about the grace period.
  2. Immediately disallow access to the product. This should be used with care, and is not recommended unless your product relies on an active internet connection.
  3. Fallback to offline license key validation if you're utilizing cryptographically signed or encrypted license keys (see the API reference for more information).

Next steps

Congrats! You've validated your first license using Keygen. Next up you could start associating machines with your users and their licenses, so that you can get a better understanding of how your users operate and where they use your product. If you have any questions about what you've learned today, be sure to reach out!