All posts

C++ guide

How to protect a simple Windows C++ application with System Locker

Start a Bedrock session at launch, verify signed responses through the reference client, and let every heartbeat rotate the session token.

By System Locker 9 min read

Adding licensing to a native Windows app doesn't have to be complex. Because the app runs on customer hardware, this guide uses the Bedrock C++ reference client to keep the authorization decision signed and current.

Copy this tutorial and its code examples as plain text for an AI assistant or a clarifying question.

1. Create a small test system

For a connected C++ application running on customer hardware, use Bedrock. Create a system, generate a test key, and keep the system ID and Bedrock signing public key in your application configuration while asking the user for their license key.

To avoid asking on every launch, save the user's license key in a convenient location, such as %APPDATA%\YourApp\license.json on Windows.

The Bedrock C++ client can derive a fault-tolerant hardware identifier. Keep the default when it fits your application, or provide a stable custom value; use 1 only when you deliberately disable device locking.

Key choice: System Locker's Bedrock C++ reference client handles signature verification, challenge generation, identity checks, and background heartbeats. Start there instead of writing the protocol by hand.

2. Start Bedrock at startup

Follow the Bedrock C++ quickstart and embed the source in your build when possible. The client verifies the signed response before it exposes the result, generates a fresh challenge for each request, and keeps the live token in its session state.

#include <syslocker/bedrock.hpp>
#include <iostream>

int main()
{
syslocker::bedrock::Config config;
config.systemId = "YOUR_20_CHAR_SYSTEM";
config.version = "1.0.0";
config.hwid = "YOUR_STABLE_HWID";
config.signingPublicKey = "YOUR_BASE64URL_RAW_ED25519_PUBLIC_KEY";

syslocker::bedrock::Client client(config);
client.onHeartbeatFailure([](const auto& failure)
{
    DisableProtectedFeatures();
    std::cerr << failure.error.message << '\n';
});

auto auth = client.authenticateWithKey("CUSTOMER_LICENSE_KEY");
if (!auth || !auth->sessionStarted)
{
    DisableProtectedFeatures();
    return 1;
}

RunProtectedApplication(client);
return 0;
}

For account authentication, call the library's password method instead. Always treat transport, signature, freshness, and authenticated denial results as failures until the client reports a started session.

3. Let Bedrock maintain the session

Automatic heartbeats are enabled by default. The client serializes them, rotates the session token after each accepted heartbeat, retries one lost response with the same challenge, and calls your failure hook when the session ends. Disable protected features from that hook instead of continuing on a stale authorization.

4. Treat the client as one layer

Your system ID is not a secret, and a desktop program can be inspected. Use the optional Program Hash when it fits your build process, keep sensitive server operations on a server you control, and make Bedrock meaningful by gating the features that require a valid session. Signed responses, rotating heartbeats, and operational logs give you more leverage than hiding one local if statement.

When your application grows

The first protected build only needs the Bedrock session flow shown above. As the application gains users, you can evaluate higher system and user limits, expanded authentication logs, more variables, reseller tooling, and higher-tier Aegis IP Intelligence when those become useful operational tools.

Ready to try Bedrock in your C++ app?

Create a system, pin its signing key, and put Bedrock in a small Windows application before you commit to a larger rollout.