> ## Documentation Index
> Fetch the complete documentation index at: https://help.cryptolens.io/llms.txt
> Use this file to discover all available pages before exploring further.

# .NET desktop application

> An older tutorial on how to integrate Cryptolens licensing into a desktop application in .NET

<Info>
  This older tutorial shows a basic VB.NET desktop integration. The examples below verify online at registration and startup. For cached offline use, follow the [offline verification guide](/examples/offline-verification).
</Info>

In this tutorial, we'll add licensing to an existing VB.NET Windows Forms application in Visual Studio. The screenshots show an older version of Visual Studio. If you are using another language, please see the [SDK guides](/libraries/index).

> If you want to jump straight into the code, please check out the [key verification](/examples/key-verification) tutorial.

<img src="https://mintcdn.com/cryptolensab/zeUJYGzRfOJq5XBx/images/digitaltools-all-features.png?fit=max&auto=format&n=zeUJYGzRfOJq5XBx&q=85&s=3c61b759b1a969052828e8597fd530fe" alt="Digitaltools All Features Pn" title="Digitaltools All Features Pn" className="mx-auto" style={{ width:"64%" }} width="337" height="294" data-path="images/digitaltools-all-features.png" />

> The example has three features (voice, audio, and converter). Features **1, 2, and 3** enable their buttons. Feature **4** marks a time-limited license; without it, this example treats the license as perpetual.

## Cryptolens .NET Client

Now we can start using all of the power of the Cryptolens Client API.

The easiest way to get Cryptolens Client API is through NuGet in Visual Studio.

1. Go to the solution explorer and right click on the project (not the solution).
2. Click on `Manage NuGet Packages...`

<img src="https://mintcdn.com/cryptolensab/UggnyNDOQ_2RBPGh/images/vs-nuget-1.png?fit=max&auto=format&n=UggnyNDOQ_2RBPGh&q=85&s=b3cf10d1e4769ab032ad8ce5a4240d2b" alt="Vs Nuget 1 Pn" title="Vs Nuget 1 Pn" className="mx-auto" style={{ width:"72%" }} width="513" height="448" data-path="images/vs-nuget-1.png" />

Now, type `Cryptolens.Licensing` into the Browse tab, select `SKM Client API` and install it.

<img src="https://mintcdn.com/cryptolensab/UggnyNDOQ_2RBPGh/images/vs-nuget-2.png?fit=max&auto=format&n=UggnyNDOQ_2RBPGh&q=85&s=c769958c472633599d6000b30cfc139e" alt="Vs Nuget 2 Pn" title="Vs Nuget 2 Pn" className="mx-auto" style={{ width:"74%" }} width="689" height="234" data-path="images/vs-nuget-2.png" />

## Adding Code

We almost have all the pieces in place to get a working licensing solution. We will cover the code in this section and look at how to retrieve **access tokens** and **public key (RSA)** later.

Our application will have two places where we will need to insert the code:

* During license key registration - the first time the user inserts a license key
* During application start - to check for an existing license on launch

The [original Digital Tools project](https://github.com/Cryptolens/Examples/tree/master/Digital%20Tools%20Collection) shows the desktop UI. Use the updated licensing snippets below when adapting it.

> Note, you can find more detailed examples of .NET [here](https://help.cryptolens.io/examples/) and other environments [here](https://help.cryptolens.io/web-api/skm-client-api). Please don’t hesitate to contact us should you have any questions.

Add these imports at the top of your main form's code file:

```vbnet theme={null}
Imports SKM.V3
Imports SKM.V3.Methods
Imports SKM.V3.Models
```

Add the following inside the main form class. `NoLicense` disables the three feature buttons until a license has been verified.

```vbnet theme={null}
Private currentLicense As LicenseKey

Private Sub NoLicense()
    currentLicense = Nothing
    Button1.Enabled = False
    Button2.Enabled = False
    Button4.Enabled = False
    Text = "Digital Tools"
End Sub
```

The examples use product ID `3349`. Replace it with your product ID in both the request and the response check. You will also need an access token with the **Activate** permission and your RSA public key; the sections below explain where to find them. For node-locked licensing, set **Maximum Number of Machines** greater than `0`. This example does not use floating seats.

### License Key Registration

Put this code in your license-entry button's `Click` handler on the main form. `TextBox1` contains the entered license key, and `Button1`, `Button2`, and `Button4` are the feature buttons in the example. Replace these control names if your form uses others.

```vbnet theme={null}
NoLicense()

Dim token = "{access token with Activate permission}"
Dim RSAPubKey = "{Your RSA Public key}"
Dim keyStr = TextBox1.Text.Replace(" ", "")
Dim machineCode = Helpers.GetMachineCodePI(v:=2)

Dim result = Key.Activate(token:=token, parameters:=New ActivateModel With {
    .Key = keyStr,
    .ProductId = 3349,
    .Sign = True,
    .MachineCode = machineCode
})

If result Is Nothing OrElse result.Result = ResultType.[Error] OrElse
   Not result.LicenseKey.HasValidSignature(RSAPubKey).IsValid() Then
    MsgBox("Unable to verify the license. Please check your key and connection.")
    Return
End If

Dim license = result.LicenseKey
If license.ProductId <> 3349 OrElse license.Block OrElse
   Not String.Equals(license.Key, keyStr, StringComparison.OrdinalIgnoreCase) OrElse
   (license.MaxNoOfMachines > 0 AndAlso
    Not Helpers.IsOnRightMachine(license, machineCode)) Then
    MsgBox("This license cannot be used by this application.")
    Return
End If

If license.F4 AndAlso DateTime.UtcNow >= license.Expires Then
    MsgBox("Your license has expired and cannot be used.")
    Return
End If

currentLicense = license
Button1.Enabled = license.HasFeature(1).IsValid() ' Voice
Button2.Enabled = license.HasFeature(2).IsValid() ' Audio
Button4.Enabled = license.HasFeature(3).IsValid() ' Converter

If license.F4 Then
    Text = "Digital Tools - " & license.DaysLeft().ToString() & " day(s) left"
End If

If license.SaveToFile() Is Nothing Then
    MsgBox("Could not save the license file. You may need to enter your key again next time.")
End If
```

This code activates the license, verifies the signature, and enables the buttons for features 1, 2, and 3. Feature 4 indicates a time limit. Once the checks pass, `SaveToFile()` saves the signed response to `licensekey.skm`, ready for the next startup. You can pass a different path to both `SaveToFile` and `LoadFromFile` if needed.

### Application Start

Put this code in the same form's `Load` handler. We load the saved file to find the license key, then activate it again to get any changes made since the last run.

```vbnet theme={null}
NoLicense()

Dim token = "{access token with Activate permission}"
Dim RSAPubKey = "{Your RSA Public key}"
Dim license = New LicenseKey().LoadFromFile("licensekey.skm", RSAPubKey)
If license Is Nothing Then Return ' Ask the user to enter a license key.

Dim keyStr = license.Key
Dim machineCode = Helpers.GetMachineCodePI(v:=2)
Dim result = Key.Activate(token:=token, parameters:=New ActivateModel With {
    .Key = keyStr,
    .ProductId = 3349,
    .Sign = True,
    .MachineCode = machineCode
})

If result Is Nothing OrElse result.Result = ResultType.[Error] OrElse
   Not result.LicenseKey.HasValidSignature(RSAPubKey).IsValid() Then
    MsgBox("Unable to verify the license. Please check your key and connection.")
    Return
End If

license = result.LicenseKey ' Use the fresh response, not the saved copy.
If license.ProductId <> 3349 OrElse license.Block OrElse
   Not String.Equals(license.Key, keyStr, StringComparison.OrdinalIgnoreCase) OrElse
   (license.MaxNoOfMachines > 0 AndAlso
    Not Helpers.IsOnRightMachine(license, machineCode)) Then
    MsgBox("This license cannot be used by this application.")
    Return
End If

If license.F4 AndAlso DateTime.UtcNow >= license.Expires Then
    MsgBox("Your license has expired and cannot be used.")
    Return
End If

currentLicense = license
Button1.Enabled = license.HasFeature(1).IsValid() ' Voice
Button2.Enabled = license.HasFeature(2).IsValid() ' Audio
Button4.Enabled = license.HasFeature(3).IsValid() ' Converter

If license.F4 Then
    Text = "Digital Tools - " & license.DaysLeft().ToString() & " day(s) left"
End If

If license.SaveToFile() Is Nothing Then
    MsgBox("Could not update the saved license file.")
End If
```

If no key has been saved or verification fails, the feature buttons remain disabled. The user can enter a key and try again.

Check expiry when the user starts a feature too, since the application may have stayed open past the expiry date. For example, begin `Button1_Click` with:

```vbnet theme={null}
If currentLicense Is Nothing Then Return
If currentLicense.F4 AndAlso DateTime.UtcNow >= currentLicense.Expires Then
    NoLicense()
    Return
End If
If Not currentLicense.HasFeature(1).IsValid() Then Return
' Run the voice feature here.
```

For long-running work, recheck expiry while it runs. To add scheduled online refresh and offline use, follow the [offline verification flow](/examples/offline-verification#refresh-and-fallback-flow), choosing your own cache storage and maximum offline age. Keep its distinction between connectivity failures and explicit rejections.

## Access Tokens

In all of the code examples, you will see variables such as `token` or `auth`. They refer to an [access token](/getting-started/access-token).

The idea behind access tokens is to allow you to:

* identify yourself with Cryptolens (authentication) - let Cryptolens know that you are you
* give your application only the permissions it needs (authorization) - for example, access to particular methods or products

An access token should only have the permissions your application needs. For example, one access token can have both the **Activate** and **Deactivate** permissions if the application registers and releases devices. The [access token guide](/getting-started/access-token) has examples and explains the Product, Key, and Feature Lock settings.

### Creating a new Access Token

In order to create an access token with the permission required by the previous example:

1. Go to ‘Your account name’ (right corner) > ‘Access Token’.
2. Click on ‘Create new Access Token’. You will now be on [this page](https://app.cryptolens.io/User/AccessToken#/newtoken).
3. Enter a name, such as “ActivateToken”.
4. Select the **Activate** permission under **License Key**. Add the **Deactivate** permission if your application releases devices and the **Get Key** permission if it calls GetKey.
5. Select the ‘Product Lock’ to be the name of your application.
6. Leave **Key Lock** and **Feature Lock** at `0` for this starting configuration, then select **Create Access Token**.
7. Copy and securely store the access token when it is shown, then replace the example's access token with yours. The value cannot be retrieved later.

### Example

You can find an example configuration in [Application activation and device release](/getting-started/access-token#application-activation-and-device-release).

## Public Key

In many cases, you will store license key data locally on your customers’ devices, partly to allow your customers to use the application offline. At the same time, you don’t want them to be able to modify the license key data (for example, the features they are entitled to and the expiration date).

Therefore, Cryptolens will sign the license key (if you explicitly tell it to do so) with your **private key**. The **public key** will allow your application to check that the license key file hasn’t been modified since it was signed by Cryptolens.

The **public key** won’t allow them to re-sign the data, only to validate it.

### Finding your Public Key

In order to find your unique public key:

1. Sign in to the [dashboard QuickStart page](https://app.cryptolens.io/docs/api/v3/QuickStart) and find **Credentials → RSA Public Key**.
2. Copy the entire public key, including the XML tags, into the `RSAPubKey` variable in both examples.

See [Where do I find my RSA public key?](/getting-started/access-token#where-do-i-find-my-rsa-public-key) for details. The public key verifies signatures; the access token authorizes API calls.

## Create a Key

We’re now ready to test the code using your account.

1. Select the product from the [list](https://app.cryptolens.io/Product).
2. Click on ‘Create a new Key’.
3. Check features 1, 2, and 3 for the functionality to enable.
4. For this example's time-limited policy, check feature 4 and set the expiry date.

Use a license from your own product with the corresponding account credentials. Test feature access, an expired time-limited license, a blocked license, and a failed connection before publishing.

### Done!

You now have a basic online activation check for registration and startup, with feature access controlled by the verified license.

## Next steps

Before publishing, review the [publishing checklist](/getting-started/checklist-before-publishing). You can then add:

1. [Get started with payment forms](/payments/payment-forms)
2. [Learn more about possible licensing models](/licensing-models/index)
3. [Understand GDPR and its implications](/security/gdpr)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.