Skip to main content

Activating a License on a Device: How Hardware IDs Work

What actually happens when an app calls activate(): hardware fingerprinting, activation limits, and reactivation.

Updated 3 min readMarkdown
Activating a License on a Device: How Hardware IDs Work

Originally published on the PermitCore blog.

You've generated a license key. Now a real customer installs your app, pastes that key, and the app calls activate() for the first time. Here's what actually happens in that call: hardware fingerprinting, activation limits, and why reinstalling on the same machine shouldn't cost a seat.

Validate vs. Activate: not the same call

These two are easy to mix up, and they do genuinely different things:

  • Validate checks that the key is real and still active. It doesn't touch the activation count, so it's safe to call on every app launch.
  • Activate does everything Validate does, plus permanently ties the key to a device and increments CurrentActivations. Call it once, the first time a customer installs your app.

What "device" actually means

For a node-locked license, the SDK needs a stable identifier for the machine it's running on: something that survives reboots and app updates but isn't trivial to spoof. There's no universal API for this across operating systems, so each platform needs its own approach:

private static string GetHardwareId()
{
    // Windows: motherboard serial + CPU ID, hashed together
    if (OperatingSystem.IsWindows())
    {
        var board = GetWmiValue("Win32_BaseBoard", "SerialNumber");
        var cpu   = GetWmiValue("Win32_Processor", "ProcessorId");
        return Sha256Hex(board + cpu);
    }
    // macOS: IOPlatformUUID
    if (OperatingSystem.IsMacOS())
        return ReadMacOsPlatformUuid();
    // Linux: /etc/machine-id
    return File.ReadAllText("/etc/machine-id").Trim();
}

All 8 official PermitCore SDKs (.NET, Node.js, Python, Java, PHP, C++, Go, Unity) include a working implementation of this, so you only write it yourself if you're integrating over raw REST.

Calling Activate

var result = await client.ActivateAsync(new ActivateRequest
{
    LicenseKey = enteredKey,
    Version    = "1.0",
    DeviceId   = GetHardwareId(),
    DeviceName = Environment.MachineName
});

if (!result.IsValid)
{
    // result.ErrorCode is one of: NotFound, ProductInactive, Expired, VersionBlocked,
    // IpBlocked, RegionBlocked, VendorSubscriptionLapsed, PoolExhausted, SeatsExhausted, WrongProduct
    ShowActivationError(result.ErrorCode);
    return;
}

SaveLicenseLocally(result);

What you see on the admin side

Every successful activation shows up immediately on the license's detail page: the request's user agent and timestamp, and (when available) a rough geographic location resolved from the request IP. That's exactly what your support team needs when a customer writes "it says I'm out of activations but I only installed it once".

Reactivating the same device

Customers reinstall software constantly: OS reinstalls, a new hard drive, a factory reset. PermitCore recognizes when an activation request comes from a hardware ID that's already recorded against that license and treats it as a reactivation, not a new seat. It doesn't consume another slot out of MaxActivations, even if the license is already fully seated.

Why this matters: without that exemption, a customer who reinstalls Windows twice on a 2-seat license would be locked out on the third install, having never used more than one machine at a time. It's a small detail, but it's the difference between licensing that gets out of your way and a support queue full of angry emails.

Deactivating a device

When a customer replaces a machine, you (or they, via the self-service Customer Portal) can remove one specific device from a license, freeing that seat for a new activation without touching the other devices on the same key.

What's next

Activation assumes your app can reach the license server. The follow-up on the PermitCore blog covers offline grace mode: keeping your app working without a connection, and how to stop a customer from editing a local file to stay "licensed" forever.

How do you identify devices in your own apps? Hashed hardware IDs, machine-id, or something else? I'd love to hear what's worked for you.

About the author

  • Software licensing with a built-in branded Store. https://permitcore.dev

No comments yet. Be the first to comment.