# Air Gapped Licensing

Air gap licensing is a useful feature for isolated environments. The concept is similar to offline license management.

The main difference is that in regular offline activation we exchange files and in air-gapped environments we cannot use files so we have to rely on exchanging strings.

In this guide you will find the instructions for implementing air-gap licensing using LicenseSpring SDK.

### Prerequisites

* Completed the [Getting Started](/sdks/introduction.md) tutorial, specifically:
  * Initialized `LicenseManager` (or `LicenseHandler`) with your configuration using the appropriate settings.
  * Activated a key-based license of any type.

### Air-Gap Configuration

The air-gap public key is necessary to verify the confirmation code obtained from the air-gap activation portal. The public key can be found on the LicenseSpring portal under Settings->Keys.

![Air-gap public key location](https://lh3.googleusercontent.com/u_fCrQWPEI-m1MphS-j7BBxMj9YMKP_NhJ4xdZdv7MNN2kckREYwPX74C-znia3gEhY2JHif_RrgPuP_i9O4i9bYgUXV-ObctBwXhHar1-OCpojiHxT6dpBXwDRvM9k_c51plU0VrHNcsITAXYoN9Q)

If the air-gap public key is not set correctly in the configuration, the activation process will raise an AirGapActivationException with the message "Confirmation code is invalid."

To set the air-gap public key in the configuration use:

{% tabs %}
{% tab title="C++" %}

```cpp
Configuration::setAirGapPublicKey("your_air_gap_public_key");
```

{% endtab %}

{% tab title="C#" %}

```csharp
Configuration.AirGapPublicKey = "your_air_gap_public_key";
```

{% endtab %}

{% tab title="Swift" %}

```swift
configuration.airgapKey = "your_air_gap_public_key"
```

{% endtab %}

{% tab title="Python" %}

```python
from licensespring.licensefile.config import Configuration

conf = Configuration(product="your_product_key",api_key="your_api_key",
                   shared_key="your_shared_key",file_key=key,file_iv=iv,
                   is_guard_file_enabled=True,
                   air_gap_public_key="your_air_gap_public_key")
```

{% endtab %}

{% tab title="Java" %}

```java
LicenseSpringConfiguration config = LicenseSpringConfiguration.builder()
  .airGappedPublicKey("<AIR-GAP-PUBLIC-KEY>")
  .build();
```

{% endtab %}
{% endtabs %}

To secure the air-gap activation, make sure that guard file option is not set to false. This feature is enabled by default and ensures that the license will not be activated multiple times with the same data, enhancing security and reliability.

{% tabs %}
{% tab title="C++" %}

```cpp
ExtendedOptions::enableGuardFile(true);
```

{% endtab %}

{% tab title="C#" %}

```csharp
ExtendedOptions.ProtectOfflineActivation = true;
```

{% endtab %}
{% endtabs %}

### License Activation

Follow these steps to activate a license via air-gap:

{% stepper %}
{% step %}

### Open the air-gap activation portal

Open the air-gap activation [portal](https://airgap.licensespring.com/) and enter the license key. It will display the key and initialization code.

![Portal step 1](https://lh3.googleusercontent.com/puNVihyrPdb3LH0ZSlrrmm1zoCFK6RVY8Cz-ol6VGHCx5kv1j4BjF2VX6dyDppxYT19I6I7qpidyVXnl_bUCrQHGv4iIuDIFoFRgRiCu_ek-fga3melSvLpa1COurqpHwE1JAaf3PR057fxrUqkoLw) ![Portal step 2](https://lh4.googleusercontent.com/p40lam5CZmpMHrZGvDMK8cy8TPYATezVPWZp0B_Ld5QAel0nkS4nHnB8o8__N0-jMxaq7vqS45kiyCvu960z1izRGH70cRwwBVtLpyIMSC1B2cSPpeqvXXFP6wWeCV8LxP7jFkKAJSAPl3ax_3LXTQ)
{% endstep %}

{% step %}

### Generate the activation code locally

Use the GetAirGapActivationCode method to get the activation code, passing the initialization code and license key as parameters. Also retrieve the hardware ID from the SDK configuration.

{% tabs %}
{% tab title="C++" %}

```cpp
auto activationCode =  licenseManager->getAirGapActivationCode(initCode, licenseKey);
auto hardwareId = configuration->getHardwareID();
```

{% endtab %}

{% tab title="C#" %}

```csharp
var activationCode = licenseManager.GetAirGapActivationCode( initCode, licenseKey );
var hardwareId = configuration.HardwareID;
```

{% endtab %}

{% tab title="Swift" %}

```swift
let activationCode = try manager.generateAirgapActivationCode(
    initializationCode: initCode,
    licenseKey: licenseKey
)
let hardwareID = configuration.hardwareID
```

{% endtab %}

{% tab title="Python" %}

```python
from licensespring.hardware import HardwareIdProvider
from licensespring.licensefile.license_manager import LicenseManager

initialization_code = "Q/MWfwp1NWAYARl8Q7KSo5Cg2YKqS2QLlnQ3nEeSBsk="
license_key = "UFF3-E9GA-VUJQ-GMLK"

manager = LicenseManager(conf)
activation_code = manager.get_air_gap_activation_code(initialization_code=initialization_code, license_key=license_key)

print("Activation code:",activation_code)
print("hardware id:",HardwareIdProvider().get_id())
```

{% endtab %}

{% tab title="Go" %}

```go
// Go SDK v2
activationCode, err := lh.GetAirGapActivationCode(initializationCode, licenseKey)
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Submit data to the portal to get confirmation and policy

Enter the license key, hardware ID, and activation code in the activation portal. It will provide the policy ID and confirmation code and make the license active on the platform.

![Portal confirmation](/files/0041d4b28d33d20c0f4efe835e7f1a7c5506e67e) ![Confirmation code](/files/e8e53c4a5a4d5f449b4e198db80d44ec2007a4ad)
{% endstep %}

{% step %}

### Download the policy file

Download the policy file from the licensing platform.

![Policy file download](/files/2d577fdf8dd7c24353f35ce521faade358e53ec1)
{% endstep %}

{% step %}

### Activate the license locally

Use the ActivateAirGapLicense method, passing the policy ID, key, confirmation code, and the path to the policy file (or the location of multiple policy files). This will activate the license on the device.

{% tabs %}
{% tab title="C++" %}

```cpp
auto license = licenseManager->activateAirGapLicense("confirmation_code", L"policy/file/path", "license_key", policyId);
```

{% endtab %}

{% tab title="C#" %}

```csharp
var license = licenseManager.ActivateAirGapLicense( "confirmation_code", "policy/file/path", "license_key", UInt32.Parse( "policy_id" ) );
```

{% endtab %}

{% tab title="Swift" %}

```swift
try manager.verifyAirgapConfirmationCode(
    confirmationCode: "confirm_code",
    licenseKey: licenseKey,
    policyID: policyID
)
    
let license = try manager.activateLicense(
    airgapPolicyFile: policyFileLocation,
    licenseKey: licenseKey,
    policyID: policyID
)
```

{% endtab %}

{% tab title="Python" %}

```python
confirmation = "ERbQBuE8giIjqMPj972Skipehqn0szQ8TH56INyo3OdtMHO1SuTVsoCOSnJWB6rml98PJ6SjybTPymOVZTG4hQ=="
policy_id = "998"
license_key = "UFF3-E9GA-VUJQ-GMLK"
policy_path = "path_to_air_lic"

manager = LicenseManager(conf)
license = manager.activate_air_gap_license(
                confirmation_code=confirmation, policy_path=policy_path, license_key=license_key, policy_id=policy_id
            )
```

{% endtab %}

{% tab title="Go" %}

```go
// Go SDK v2
ld, err = lh.ActivateAirGapLicense(confirmationCode, policyPath, licenseKey, policyId)
```

{% endtab %}
{% endtabs %}
{% endstep %}
{% endstepper %}

### Air-Gap license fields

License data contains information if the license was activated using the air-gap approach and the license policy id.

To get the corresponding fields use:

{% tabs %}
{% tab title="C++" %}

```cpp
bool isAirGapped = license->isAirGapped();
std::string policyId = license->policyId();
```

{% endtab %}

{% tab title="C#" %}

```csharp
bool isAirGapped = license.IsAirGapped;
string policyId = license.PolicyId;
```

{% endtab %}

{% tab title="Swift" %}

```swift
license.isAirGapActivated
```

{% endtab %}

{% tab title="Python" %}

```python
print("is air gapped:",license.is_air_gapped())
print("policy id:",license.policy_id())
```

{% endtab %}
{% endtabs %}

### License deactivation

The air-gap deactivation process is similar to the air-gap activation. It contains the following steps:

{% stepper %}
{% step %}

### Open the air-gap portal and switch to deactivation

Open the air-gap activation [portal](https://airgap.licensespring.com/) and switch to license deactivation. Enter the license key; it will display the key and initialization code.

![Deactivation portal step 1](/files/f8c3ff0d1486a6e4d07b8fe8ab9269fadcd24794) ![Deactivation portal step 2](/files/d808dedfbe9684e581b863a1a0e24797219366ce)
{% endstep %}

{% step %}

### Generate the deactivation code locally

Use the GetAirGapDeactivationCode method to get the deactivation code, passing the initialization code and license key as parameters. Also retrieve the hardware ID from the SDK configuration.

{% tabs %}
{% tab title="C++" %}

```cpp
auto deactivationCode =  licenseManager->getAirGapDeactivationCode( initCode, licenseKey );
auto hardwareId = configuration->getHardwareID();
```

{% endtab %}

{% tab title="C#" %}

```csharp
var deactivationCode = licenseManager.GetAirGapDeactivationCode( initCode, licenseKey );
var hardwareId = configuration.HardwareID;
```

{% endtab %}

{% tab title="Python" %}

```python
deactivation_code = license.get_deactivation_code(initialization_code)

print("Deactivation code:",deactivation_code)
print("hardware id:",HardwareIdProvider().get_id())
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### Submit data to the portal to get confirmation

Enter the license key, hardware ID, and deactivation code in the activation portal. It will provide the confirmation code and make the license inactive on the platform.

![Deactivation confirmation 1](/files/54a4adbb0c105198d21f241540b926360a6c46bb) ![Deactivation confirmation 2](/files/49316190c6b2ba2a8f321a3c87605bbe88811d33)
{% endstep %}

{% step %}

### Deactivate locally

Use the DectivateAirGapLicense method, passing the confirmation code. This will deactivate the license on the device and remove the local license file.

{% tabs %}
{% tab title="C++" %}

```cpp
license->deactivateAirGap("confirmation_code");
```

{% endtab %}

{% tab title="C#" %}

```csharp
license.DeactivateAirGap( "confirmation_code" );
```

{% endtab %}

{% tab title="Python" %}

```python
confirmation_code="your_confirmation_code"
license.deactivate_air_gap(confirmation_code)
```

{% endtab %}
{% endtabs %}
{% endstep %}
{% endstepper %}

### Errors

During air-gap activation, various exceptions may occur, including those encountered during regular activation. Additionally, in .NET, not all versions are supported. In such cases, a LicenseSpringException with the message "Air gap feature is not supported on .NET Framework 3.5-4.6" may be thrown.

AirGapActivationException can be thrown during license activation and deactivation in case confirmation code verification failed.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.licensespring.com/sdks/tutorials/licensing-scenarios/air-gapped-licensing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
