Offline Licensing: complete guide for software developers

Published on: August 11, 2022
hero
Table of Contents:

Some computers will not have an active internet connection or are behind a firewall preventing online activation. For this reason, we developed a mechanism to allow the activation and deactivation of licenses in an offline environment. In this tutorial, we will learn the basics of Offline Licensing using the LicenseSpring C++ SDK.

Follow the linked video for an overview on LicenseSpring’s Offline License Activation.

This guide will walk you through implementing offline licenses within the LicenseSpring C++ SDK. By the end of this tutorial, you should understand how to activate, deactivate, and check licenses without requiring an active internet connection. We will also look into total activations and max activations, the license types supported, and the differences between offline and online licensing. We will create a ChatBot that successfully activates, deactivates, and uses the local license file for local license checks, all without requiring an active internet connection.

For more information, look into our Offline Licensing Documentation.

Note: Since this article is a continuation of the Getting Started Tutorial, it is assumed that readers meet the prerequisites previously stated. Readers should also have a thorough understanding of license activation, deactivation and checking. 

Sections:

  • Implementing the Offline License ChatBot
  • Offline Activation
  • Offline Deactivation
  • Total Activations and Max Activations
  • License Types Supported
  • Using the Local License File for Local License Checks
  • Differences between Online License Activations and License Checks 
  • Anti-Clock Tampering Within Local Licenses
  • Common Problems

Implementing the Offline License ChatBot:

Offline Activation:

Creating Offline Activation Request File:

The first step to activating a license offline is to create an offline activation request file. This can be done by using the following function:

cpp
1 auto filePath = licenseManager->createOfflineActivationFile(licenseId);

This function creates an offline activation request file with the path and name specified in the parameter ‘path’, for the key-based/user-based license defined in LicenseID. If ‘path’ is left empty, the default path that the offline activation request file will be created in is the desktop, and the default name will be ls_activation.req: C:\Users\%USERNAME%\Desktop\ls_activation.req. 

Uploading Offline Activation Request File to LicenseSpring Offline Portal:

Once you have your offline activation request file, you will need to upload it to the LicenseSpring offline portal. Note: this will require a computer with online access.

Offline Licensing Portal

After uploading, you will be given an offline activation response file, with the name ls_activation.lic.

Activating Offline Activation Response File:

Finally, to activate the license offline on a device, you can use activateLicenseOffline(path) as shown below:

cpp
1 license = licenseManager->activateLicenseOffline(path);

You will have to specify the name and path of the offline activation response file in the parameter ‘path’. If ‘path’ is left empty, the default path and name it will search will be the desktop with the name ls_activation.lic:  C:\Users\%USERNAME%\Desktop\ls_activation.lic.

Offline Deactivation:

Creating Offline Deactivation Request File:

Once a license has been activated, it can also be deactivated using a similar process. Within the Chatbot, the function that creates this offline deactivation request file is:

cpp
1 auto filePath = license->deactivateOffline();

You can also provide an optional parameter into the deactivateOffline() to provide an alternative path for the deactivation request file to be created and stored. Leaving the parameter empty uses the default file path, which saves the file to the desktop. After we create the deactivation file, to eliminate any local license that we have, we run:

cpp
1 licenseManager->clearLocalStorage();

Uploading Deactivation Request File:

Now that you have created your deactivation request file, you need to return to the Offline Licensing Portal to upload. After uploading the deactivation request file, this updates the LicenseSpring platform to show that the license is no longer active and unbound from the device.

Offline License Refresh:

Offline license refresh assists users in refreshing their activated offline license, typically used when aspects of the license were altered on the backend. For example, if you wish to add a new feature but do not want to reactivate the license. To refresh a license offline, find the license on the LicenseSpring platform and go to the Devices tab.

License Refresh

We incorporated the ability to update licenses using this feature in our Chabot. The line of code that does the updating is:

cpp
1 if (license->updateOffline(path));

The path within the parameter is the path to the license_refresh.lic file which we downloaded from the page as shown above.

Example Usage:

Since the portal requires a network connection, there are specific ways for offline license activation to work. One way would be to:

  1. Create the offline activation request file on a computer without internet access.
  2. Transfer that file via USB to a computer with an internet connection.
  3. That computer can upload that file to the portal and retrieve the offline activation response file.
  4. Transfer it back to the computer without internet access, once again via USB. 
  5. Finally, the offline computer can activate its license, creating a local license file. 

A similar process can be done for deactivation, but without having to transfer back the offline activation response file.

Offline/Online Hybrid Code:

If there are cases where you will need both online and offline deactivation, activation, and checks, you can use the code isOnline() to check when you should be doing offline deactivations/activations/checks, and when you should be doing online deactivations/activations/checks.

cpp
1 if( licenseManager->isOnline() )

Reasons Why The Request File May Not Generate a License File When Uploaded:

The offline license activation process will fail for any of the following reasons:

  • Total activations on the account have reached max activations (see Getting Started).
  • License is expired or disabled.
  • Incorrect license credentials.
  • Incorrect product configuration (i.e. Shared key, API key, and/or Product code).
  • License is within an account using free tier.

License Types Supported:

Offline activation is supported for Perpetual, Consumption, and Time-Based licenses. Offline activation does not work for Subscription-Based licenses.

Differences with Online License Activations and License Checks:

Since we perform the operations offline, we do not have direct access to the backend. Due to this roadblock, offline licensing uses a more gradual approach. Rather than activating the license in one line using activateLicense(), we use createOfflineActivationFile() and upload the file to the offline portal to receive the offline response file. This response file is put back into the program to activate the license.

Checking licenses is similar since we do not have access to check() when running our program offline. As a result, we only inspect the local license when checking offline, instead of the backend and locally. Best practices include doing localCheck() consistently to confirm your license is still valid.

Note: to use localCheck(), a valid pointer to the license is required.

Guard Files:

Guard files prevent users from using the same license request file and are automatically enabled within extendedOptions. Guard files can be disabled in the extendedOptions constructor or by running enableGuardFile( false ). When this is enabled, a guard file is created in the folder where the license will be created and where we store the SDK logs. These are saved in a hidden file called guard file, and if someone removes this file or tries to edit this file the license activation will fail. This file is created as soon as you create the request file for offline activation, and this guard file is valid and should exist when a user is submitting a response file.

Anti-Clock Tampering within Local Licenses:

Manually editing a computer’s clock time into the past and running a local license check is prevented in LicenseSpring. If the platform sees that the computer's local time is before the last time the license was checked, it can confirm that the clock has been tampered with. Also, the checker examines only UTC time, so time zones do not impact the anti-clock tampering mechanism.

Common Problems:

GetCurrentLicense() not returning null even though the local license file has been deleted from the device: 

When the local license file is deleted using something like license->deactivate( true ), the file will still remain in memory, until it is cleaned out, or the program ends. GetCurrentLicense() will always check memory first to find the local license, and if it finds it, it will not go into your storage to look for it, thus it will return the pointer to the location in memory where local license still exists. There are multiple ways to work around this issue:

  • Close the program, which will clean out the local license from memory, then run it again normally.
  • Use clearLocalStorage() (and set license to nullptr), which will, among other things, also clean out the local license from memory.
  • Use ReloadLicense() instead of GetLocalLicense(). ReloadLicense() is similar to GetLocalLicense(), except that it will never check memory to see if the local license exists over there. It will always go into the folder where the local license is stored and grab that file and put it in memory each time it is called.

Note: LicenseFileException listed in docs but doesn’t exist

updateOffline() and activateLicenseOffline() throwing exceptions:

  • The most common case for either of these throwing exceptions is that the hardware ID in the response file does not match the hardware ID of the device. This will throw a SignatureMismatchException. For updateOffline(), make sure the device you created the update response file on the LicenseSpring platform matches the device you try to update. For activateLicenseOffline(), make sure the device you used to create the activation request file is the same one you use the activation response file for.

External changes on the LicenseSpring platform that adjust the state of the device, i.e. resetting, disabling, will not be reflected in the program, even with checks.

  • Since we’re offline, these changes will not be updated on the user-end. Disabling will not set user’s licenses to inactive, but will prevent users from activating and deactivating any licenses until it is enabled again. Resetting also does not set user’s licenses to inactive, however deactivating all licenses on the user-end should update everything correctly.