AtlasAuth Overview
AtlasAuth is an authentication and licensing platform for desktop apps written in C++ and C#. It lets you put your app behind user accounts and/or license keys, kill compromised or revoked sessions in near real time, push remote settings through app variables, and collect client-side logs. You do all of this without shipping a secret inside your binary.
This page covers what AtlasAuth is, how the pieces fit together, the security model that makes it hard to spoof, and the core concepts you will use when you integrate the SDK.
What problem it solves
Client-side licensing is hard because the client is hostile ground. Whoever runs your app controls the machine, the network, and the process memory. There are two classic ways things break:
- Embedded secrets. If your SDK ships an API secret or HMAC key so it can "prove" a response is genuine, that secret sits in the binary. A determined attacker pulls it out and forges any response they want ("you are licensed forever").
- MITM / fake server. If the client just trusts whatever JSON comes back over HTTPS, an attacker who redirects the host (hosts file, DNS, a patched binary, a local proxy) can return a hand-written
{"ok": true}and skip every check.
AtlasAuth solves both. It signs every security-relevant response with an ECDSA P-256 private key that never leaves the server, and it puts only the matching public key in your SDK. The client verifies signatures. It holds no secret to leak.
Architecture
AtlasAuth has three layers.
+-------------------------+ HTTPS / TLS +----------------------------+
| Your app (C++ / C#) | POST JSON ───────────▶ | Cloudflare Worker |
| + AtlasAuth SDK | | (atlasauth.cc/api/v1) |
| | ◀──── signed envelope | - validates request |
| - app_id (uuid) | | - signs payload (P-256) |
| - app PUBLIC key | | - holds PRIVATE key |
| - generates nonces | +-------------+--------------+
| - verifies signatures | |
+-------------------------+ | service key
▼
+----------------------------+
| Supabase (Postgres) |
| - apps, users, keys |
| - sessions, variables |
| - bans, logs |
+----------------------------+- The SDK runs inside your app. It knows two public facts, your
app_id(a UUID) and your app's public key (SPKI DER, base64), and nothing secret. For each request it makes a fresh random nonce, sends JSON to the API, verifies the signature on every signed response, and only then trusts the contents. - The Cloudflare Worker is the API at
https://atlasauth.cc/api/v1. Every endpoint isPOSTwithContent-Type: application/json. The Worker checks the request, talks to the database, and signs security-relevant responses with the app's ECDSA P-256 private key. That private key lives server-side only. - Supabase (Postgres) is the source of truth: your apps, users, license keys, sessions, app variables, bans, and logs. The Worker reaches it with a service key that also never touches the client.
The trust boundary is the signature. Every decision the client makes (authenticated or not, banned or not, app enabled or not) comes from a payload that carries a valid server signature. If it does not, the client throws it away.
Security model
Why response signing beats embedded secrets
| Embedded secret (HMAC / API key) | AtlasAuth (asymmetric signing) | |
|---|---|---|
| What's in the binary | A secret that can verify and forge | A public key that can only verify |
| Extract the binary secret | Attacker can mint valid responses | Attacker still cannot forge, no private key |
| Fake/MITM server | Defeated only if the client also checks a secret it holds | Fake server cannot produce a valid signature |
| Key compromise blast radius | Total, secret == ability to forge | Rotate the server private key; clients ship a new public key |
With AtlasAuth, the most an attacker who fully reverse-engineers your binary gets is your app_id and your public key. Neither one lets them forge a signed response. To forge a response they would need the private key, which only exists on the server.
What client-side auth can and cannot guarantee (honest version)
AtlasAuth makes it cryptographically infeasible to forge a server response or replay an old one. That is a real, strong guarantee, and it beats the most common cracking approaches (fake server, MITM, response replay).
It does not (and no client-side system can) guarantee that code on a machine the attacker fully controls behaves honestly. AtlasAuth cannot stop an attacker who:
- Patches your binary to ignore the verification result (for example, NOPs out the "if signature invalid, abort" branch).
- Tampers with process memory at runtime to flip an
isAuthenticatedboolean after a legitimate check passed. - Rips out your protected feature code entirely and runs it standalone, if it never really needed the server.
Here is the right way to think about it. Signing protects the integrity of the conversation with the server. It does not protect the integrity of your process against its owner. So make the server the source of truth for things that matter. Deliver real secrets, content, or computation from the server only after a verified, authenticated check, so a cracked client has nothing to bypass *to*. The threat model in security.md covers the leftover risks and mitigations in detail.
Core concepts
Apps
An app is one product you protect, identified by a UUID app_id. Each app has its own ECDSA P-256 keypair (private on the server, public in your SDK), plus its own users, keys, variables, and settings (forced version, heartbeat interval, HWID lock policy, whether self-registration is allowed). An app has a status (below) that can disable every client instantly.
License keys
A license key grants access. A key carries an expiry (a unix timestamp, or null for lifetime), an optional level, and binding state (the HWID it locked to on first use). Keys work in two flows: redeemed during register to create a user account, or used directly via license for key-only login with no username/password.
Users
A user is a username + password account, created via self-register (if the app allows it) or by you in the dashboard. A login returns the user's expiry, level, created_at, last_login, and remaining_seconds. Users can be banned.
Variables
App variables are server-stored key/value strings you fetch at runtime via /var. They are handy for remote config, feature flags, or sending data only to authenticated sessions. A variable can be marked auth-required (returned only to an authenticated session; otherwise ok:false, code:"auth_required") or public (returned on any valid session).
Sessions
A session is opaque, server-side state. init mints a session token; login/register/license mark it authenticated; you send the token in every later call. Killing a session server-side invalidates it on the user's next check heartbeat. The lifecycle is:
init ─▶ login | register | license ─▶ check (loop every `heartbeat` s) ─▶ logoutHWID
A hardware ID is an opaque per-machine string the SDK computes. By default it is base64(SHA256(...stable hardware ids...)). If you set a secret seed, the SDK instead returns base64(SHA256("atlasauth-hwid-seed|" + seed)), which is reproducible on any machine that knows the seed and unguessable to anyone who does not. The server binds the first HWID it sees for a key/user and then requires an exact match. HWID bans match the full string, exact-equality only, so there are no false positives. See security.md for details.
Logs
The /log endpoint sends client-side events (info / warn / error + a message) to your app's log and an optional Discord webhook. It is best-effort and never blocks the client.
App status
Every init and every check returns app_status: "active", "maintenance", or "disabled". If status is not active, the client shows status_message and exits. Because check re-reads status every heartbeat, you can disable an app or put it into maintenance from the dashboard and every running client drops within one heartbeat interval. It is a remote kill switch.
Next steps
quickstart.md: create an app, copy yourapp_idand public key, generate a key, drop in the SDK, log in, and start the heartbeat, with minimal C# and C++ snippets.security.md: the full anti-spoofing explanation. ECDSA P-256 signing, nonce/replay defense, timestamp skew, TLS, key handling, HWID bans, the app-status kill switch, and the threat model with leftover risks and mitigations.
