Skip to main content

FAQ

Common questions from customers integrating Obsidian into a shipping product. If your question is not here, check the Security Practices page or one of the SDK guides.

Which operating systems does Obsidian support?

Client-side, Obsidian is Windows-only. Every SDK targets Windows exclusively, and there is no macOS or Linux build path today.

The C# SDK requires .NET Framework 4.7.2 or later and pulls in System.Management, Microsoft.Win32, and System.Web.Script.Serialization, all Windows-only assemblies. It does not run on .NET Core, .NET 5, or .NET 6/7/8; JavaScriptSerializer was intentionally left behind in that split. The Python SDK is compiled as obsidian_sdk.cp312-win_amd64.pyd and reads HWID components through winreg, wmic, and PowerShell. The C++ SDK ships as obsidian_x64.dll and obsidian_x86.dll built with MSVC against the Windows 10 SDK or newer.

The dashboard and API run in your browser and are OS-agnostic.

Can I ship on macOS or Linux?

No. The SDKs will not load or run on those platforms, and the compiled artifacts (a PE DLL, a Windows-only PYD, an assembly that references WMI) confirm it.

If your product must run cross-platform, you have two options:

  • Wrap only the Windows build with Obsidian and gate downloads by OS in your storefront.
  • Talk to your account owner about a custom server-only integration where your macOS or Linux client speaks HTTPS to the Obsidian API directly. You lose HWID lock, screenshot capture, and the C++ heartbeat, but request signing and response signing still work.

Which Python version do I have to pin?

CPython 3.12 x64 on Windows. Exact.

py -3.12 -m pip install requests cryptography

A .pyd built for 3.12 will not import into 3.11, 3.13, or 3.14. If your app bundles a different interpreter (for example, a PyInstaller build using 3.11), rebuild it against 3.12 or request a matching SDK from your account owner. See the Python SDK page for the bundling checklist, including PyInstaller flags.

How do I obfuscate my own executable?

Obsidian does not obfuscate your binary. It authenticates it and adds runtime tripwires (heartbeat, code hash, response signing), but the bytes of your .exe are your problem.

Recommended stack for a Windows release build:

  • Strip debug symbols and PDB paths from the final binary.
  • Run a commercial protector such as VMProtect or Themida on your executable before shipping. The Obsidian client itself is already protected inside its DLL, PYD, or assembly; your code needs the same treatment separately.
  • Use link-time code generation and /GL /LTCG for C++ builds.
  • For C#, apply an obfuscator that supports .NET Framework 4.x assemblies (ConfuserEx, Eazfuscator, or similar) before code-signing.
  • Sign the final binary with an EV code-signing certificate so SmartScreen does not blackhole your users.
tip

The C++ SDK heartbeat accepts a code_hash_or_null argument on every beat. Push a hash of your own .text section there so the server can spot in-memory patching even if your binary is unprotected on disk.

Does Obsidian stop reverse engineering?

No. Nothing running on a user's own machine can. What Obsidian does do is make a bypass on one machine useless anywhere else.

The stack the client cannot skip:

  • SPKI pinning against the server cert (SHA-256 4e93dd1f9ef0f20f84b93cac3bed8e279309fd07756e7835806f1711995c78ac), so a MITM proxy or a bad root CA cannot rewrite responses.
  • Ed25519 signatures on every reply, so a fake server or a hosts-file redirect cannot fabricate a success. See response signing.
  • HMAC-SHA256 request signing with a fresh 16-byte nonce and a UTC timestamp per call.
  • HWID lock enforced on the server, not by a client boolean the attacker can flip.
  • Rotating heartbeat tokens (C++ SDK). Fork the session and both copies die.
  • Server-side kill switches. Disabling an app returns Application disabled (or the custom disabled_message you set). Pausing keys returns License validation is temporarily paused for this application. from /register and /license, and Access is temporarily paused for this application. from /login. A banned license returns License key is banned from /register and /license. HWID and IP blacklists are checked on every client endpoint.

Assume the attacker owns the process. Treat the server as the source of truth for who is allowed to run, and design gating so no single bypass scales past the machine it was found on.

What happens if the Obsidian server is down?

Every SDK call fails closed. The SDKs verify the Ed25519 signature on every response, so there is no cached-success mode and no offline fallback.

Init(), Login(), Register(), and License() throw ObsidianException (C#) or ObsidianError (Python). The C++ obsidian_*_v2 calls return non-zero with an error message written to out_err.

If you need graceful degradation, wrap the call at your entry point and decide what "server unreachable" means for your product. Common patterns:

  • Hard fail: display "authentication service unavailable, retry later" and exit. This is the default and the safest.
  • Grace period: cache the last successful login timestamp in a signed local file and allow a 24 or 48 hour offline window. Anything longer defeats the point of a server-side kill switch.
  • Read-only mode: allow the app to launch but disable premium features until the next successful Login().

Check status.obsidianauth.com or your account contact for planned maintenance windows.

How do refunds and chargebacks work?

Refunds are handled by whichever storefront processed the payment. Obsidian only tracks the license and its state.

When you or your reseller refunds a customer:

  1. Open the Manage Keys panel for the affected application.
  2. Find the license by key, buyer username, or HWID.
  3. Click Ban on the row. The license status flips to banned, and the next /api/client/license or /api/client/register call for that key returns 403 License key is banned.
  4. If the user has a bound account, ban the user under the Users tab as well, so login-based re-entry is closed too.
info

When a banned key is bound to a user account, /api/client/login returns 401 Invalid username or password for that user rather than a distinct "banned" message. The ban is enforced during credential lookup, not surfaced separately, so your UI should not try to distinguish the two states.

Chargebacks are the same flow with one addition: bulk-ban the HWID that was on the license, so the same machine cannot rebuy under a new email and immediately reactivate. Use the Blocked IPs and HWID blacklist controls under the app's Security tab.

GDPR: how do I delete an end user's data?

The dashboard supports hard deletion. Under Users, select the user and choose Delete. This removes the row from end_users and cascades the delete to associated activation screenshots stored under the app.

License records are retained separately because they represent a financial transaction. If the request also covers the license itself, ban the key first, then delete it from Manage Keys. The audit log entry for the deletion is retained under the application's Logs tab as legal proof that the deletion occurred, with the username replaced by a redaction marker.

For subject access requests, export the user row plus their activation log from the Users tab. The export includes username, HWID, last IP, last geo, login history, and activation screenshots. It does not include the password hash, which is one-way and not personal data under GDPR guidance.