Requirements
- C++17 or later
- libsodium: Ed25519 signature verification
- OpenSSL: SHA-256 and helpers
- libcurl: HTTPS requests
Installation
There is no central C++ package registry. Consume the official SDK from GitHub; AuthForgeCC/authforge-cpp (use a release tag under Releases).Option A: FetchContent (CMake)
Pin a tag (for example v1.4.0) and link the authforge_sdk target:
1.4.0 changes the
AuthForgeClient class layout. When upgrading, rebuild everything that includes authforge_sdk.h.Option B: Install prefix + find_package
Build and install the SDK, then point CMake at the prefix:
Dependencies
Install development packages for libsodium, OpenSSL, and libcurl before configuring CMake. Examples:- Linux (Debian/Ubuntu):
sudo apt install libsodium-dev libssl-dev libcurl4-openssl-dev - macOS (Homebrew):
brew install libsodium openssl curl; setCMAKE_PREFIX_PATHif CMake does not find Homebrew prefixes. - Windows: Use vcpkg for
libsodium,openssl, andcurl, then pass-DCMAKE_TOOLCHAIN_FILE=.../vcpkg.cmake.
Quick start
Constructor parameters
ttlSeconds (grace period)
Requested session token lifetime in seconds for /auth/validate, passed as the 9th constructor parameter. This is the grace period: how long the app keeps running on the signed session without contacting AuthForge. Pass 0 (or omit) to accept the server default of 24 hours. The server clamps to [3600, 604800] (1 hour to 7 days). The requested TTL is preserved across heartbeat refreshes, and apps relying on the grace period alone can extend their window up to 7 days.
Billing
- Each successful
Login()orValidateLicense()costs 1 credit (one/auth/validatedebit). - The grace period is free: local session re-verification makes no network calls and consumes no credits.
- Online check-ins (if enabled) cost 1 credit per 10 successful heartbeats (billed on every 10th call).
- With online check-ins, revocations take effect on the next check-in regardless of interval; without them, at session expiry.
Login
true on success, false otherwise. On success, a background thread re-verifies the signed session locally during the grace period (and sends online check-ins if OnlineHeartbeat::On was passed).
Validate license (no session)
/auth/validate request and Ed25519 verification as Login, without persisting session fields on the client or starting the background thread. Does not invoke the failure callback or std::exit on error; inspect valid / errorCode instead.
Failure callback
If authentication fails, an online check-in fails, or the session expires, the SDK calls youronFailure callback. Returning normally from the callback keeps the process running; if the callback throws, the SDK calls std::exit(1). Without a callback (1.4.1+), a transient background check failure writes AuthForge: background check failed (<code>); retrying next interval to std::cerr and check-ins continue; every other failure (a rejected Login, a definitive check-in answer, the grace period running out) calls std::exit(1).
Typed errors and check-in failures (1.4.0+)
Login(), SelfBan(), and background checks pass an authforge::AuthForgeError as ex (reach it with dynamic_cast from the const std::exception*), with code(), isTransient(), and isFatal(). For server codes ex->what() equals the code. A non-2xx response with a JSON body yields the server’s clean code on both login and check-ins (what() is invalid_key, not http_error_401: {...}; this also applies to ValidateLicenseResult::errorCode); only non-JSON error pages become http_error_<status>. authforge::IsTransientErrorCode(code) exposes the same classification.
- A transient failure after the session’s signed TTL has passed is reported as
session_expired(definitive). The grace period check also ends withsession_expired. - On check-ins,
hwid_mismatchmeans this device’s HWID is no longer bound to the license (for example after an HWID reset), andblockedmeans the HWID or IP is blacklisted or not on the app’s whitelist. unexpected_responsemeans a check-in failure body that is not{"status":"failed","error":"<code>"}(for example a proxy error in JSON). It is never treated as a verdict;what()keeps the rawstatus/error.- Unknown snake_case server codes are passed through as-is instead of becoming
unknown_error.
rate_limited (or HTTP 429 without an error code) is retried after 2s, then 5s; no_credits, demo_quota_exceeded, and app_burn_cap_reached also use HTTP 429 but are not retried, and the next check-in happens at the next interval; a network failure is retried once after 2s, then fails with network_error or timeout (what() starts with url_error: ).
Thread safety. Background onFailure calls run on the heartbeat thread with no SDK lock held. Calling Logout(), IsAuthenticated(), or Login() from the callback, or destroying the client inside it, is safe. Logout() stops check-ins without blocking; the destructor stops the heartbeat thread and joins it (waiting for an in-flight check-in, if any).
To tolerate short outages but shut down on a definitive answer, have the callback signal your main thread and let the main thread save and exit:
PostMessage on Windows or QMetaObject::invokeMethod in Qt) and close the main window normally. Calling std::exit(1) inside onFailure is a last resort: it skips the destructors of objects on every thread’s stack, so save the user’s work first.
Grace period and online check-ins
By default, the app runs through the grace period after activation: the SDK re-verifies the signed session locally, makes no network calls, and stops when the session expires. Opt in to online check-ins for fast revocation and concurrent-use detection by passingauthforge::OnlineHeartbeat::On as the 4th constructor argument:
Offline license files (.authforge)
For machines that never connect to the internet, the operator mints a signed offline license file in the dashboard or Developer API (1 credit). The SDK verifies it locally with your public key and the machine HWID; no network, no check-ins, and online Login() is untouched. Pass an empty appSecret so the air-gapped binary does not contain the App Secret.
onFailure("offline_login_failed", &exc) with exc.what() set to the code and return false (never std::exit). Codes, in check order: bad_armor, bad_signature, unsupported_version, malformed_payload, wrong_app, expired, hwid_mismatch. client.VerifyLicenseFile(pathOrText) and the free function authforge::VerifyLicenseFile(text, appId, publicKeys, hwid) run the same checks without touching state and return a VerifyLicenseFileResult. Issued files cannot be revoked remotely; they stay valid until their own expiry. CreateActivationRequest() produces the .authforge-request the operator uploads; hostname is omitted unless includeMachineName is set. See Activation requests.
Migrating from "SERVER" / "LOCAL"
The legacy constructors taking a "SERVER" or "LOCAL" string as the 4th argument are deprecated but still work:
"LOCAL": drop the argument; the grace period is now the default."SERVER": passauthforge::OnlineHeartbeat::Oninstead.