C++ SDK
Needs libcurl and OpenSSL. Build and link flags are at the top of atlasauth.cpp.
Download atlasauth.h and atlasauth.cpp from the sidebar and add them to your project. Create a client with your app id and public key from the dashboard:
atlas::Client client("YOUR-APP-ID", "YOUR-PUBLIC-KEY");Init
Call first. Opens the session. Returns false if the app is in maintenance or disabled, or your version is blocked.
if (!client.init())
{
std::cout << client.lastError() << "\n";
return 1;
}Login
Username and password.
if (!client.login(username, password))
{
std::cout << client.lastError() << "\n";
return 1;
}Register
Create an account that redeems a key. The user logs in with username and password after that.
if (!client.register_(username, password, licenseKey))
{
std::cout << client.lastError() << "\n";
return 1;
}License
Sign in with just a key, no account.
if (!client.licenseLogin(licenseKey))
{
std::cout << client.lastError() << "\n";
return 1;
}Heartbeat
Start it right after init, before login. You do not need to be logged in. It pings the server on an interval and kicks the user when their key expires, their session is killed, the app goes down, or they are banned.
It is also an anti-tamper check. If the heartbeat thread is paused or suspended, the session goes stale and the user is kicked. Both the server and the SDK measure the gap, so freezing the client clock does not hide it. Running it from init catches a paused thread before the user ever logs in, which is when crackers try to jump past auth.
client.startHeartbeat([](std::string reason)
{
std::cout << reason << "\n";
std::exit(0);
});Gate anything sensitive on sessionAlive(). It is false the moment the heartbeat stalls, so a frozen heartbeat thread stops your app.
if (!client.sessionAlive()) return; // heartbeat stalled or session dead
// run protected codeVariables
Fetch an app variable. Empty if it does not exist, or if it is login-gated and you are not logged in.
std::optional<std::string> value = client.var("download_url");Protect content
Stops a cracked copy from working. Put the values your app needs (a download link, an unlock code, a config string) in the dashboard as secret variables, then read them at runtime. A real logged-in user gets the real value. A cracked or faked copy gets a wrong one, so the app can't run.
Read a value and use it:
long long offset = client.secretLong("aim_offset");
write(gameBase + offset, value);For a real user offset is correct. For a cracked copy it is wrong, and the app breaks on its own. secretString returns text, secretBytes returns raw bytes. Don't check if it worked, just use it.
Protect a few small values you actually use, not one big value at startup, and change them when you ship an update.
To ship a whole encrypted file or blob inside your app: enter the variable name and click Generate to make a key, encrypt your value in the Encrypt a value box, paste the result into your app, then unlock it at runtime with the same variable name.
if (auto url = client.decryptSecret("content_key", cipher)) use(*url);A wrong or missing key makes decryptSecret return empty instead of a value, so a cracked copy gets nothing, not the real value. The difference from secretLong: that one hands back a wrong value, decryptSecret returns empty. Either way the cracked copy never gets the real thing. The value is also locked to this app and variable name.
Log
Send a line to the app log.
client.log("info", "started");Status and news
Public. No login needed.
auto status = client.status(); // status->status, status->online
auto news = client.news(); // std::vector<NewsItem>HWID seed
Optional. A fixed seed gives the same HWID on any machine, so you can move your own key. Others cannot use it.
atlas::Client client("YOUR-APP-ID", "YOUR-PUBLIC-KEY");
client.setHwidSeed("your-secret-seed");Logout
client.logout();Reading the user
After a successful login:
client.username(); // std::string
client.expiryUnix(); // std::optional<int64_t> (empty = lifetime)
client.loggedIn(); // bool
client.lastError(); // last failure messageHarden further
The SDK verifies every response and delivers your keys only to a live session, but the binary still runs on the attacker's machine. To raise the cost:
- Consume decrypted values, never gate on a bool. If flipping one branch unlocks your app, nothing else here helps.
- Encrypt more, smaller pieces through the secret channel, and re-key them each update.
- Run a protector on your shipped build (VMProtect or Themida). Virtualize the few functions that verify and decrypt.
- Code-sign your build so users can spot tampered copies.
- Rotate your app key if you suspect a leak, and watch HWID churn and sessions in the dashboard.
Optional: setPinnedPublicKeys("sha256//PRIMARY=;sha256//BACKUP=") before init() pins the server's TLS key so a local proxy cannot read traffic. Ship two pins and only use it if you manage the cert key, or a rotation locks users out.
No client-side check is unbreakable by someone who owns the machine. These raise the time and effort, they do not make it impossible.
