License key input UX
Desktop apps
Use a dialog or popup window on first launch. After successful validation, store the key locally (e.g., in a config file, registry, or app data directory) so users don’t re-enter it every time. Provide a “Deactivate” or “Change License” option in settings.CLI tools
Support multiple input methods:- Command-line flag:
--license-key XXXX-XXXX-XXXX-XXXX - Environment variable:
AUTHFORGE_LICENSE_KEY - Config file:
~/.yourapp/config.jsonor~/.yourapp/license - Interactive prompt: Ask on first run if no key is found
Game mods and plugins
Read the key from a config file in the mod/plugin directory (e.g.,plugins/your-mod/license.txt or config.yml). Don’t block the game’s main thread with a dialog — load the key at plugin initialization and fail gracefully.
Error handling on login
Handle each error code with an appropriate user-facing message. Never expose internal details to end users.| SDK error | Cause | What to show the user |
|---|---|---|
invalid_app | Your App ID or Secret is wrong | ”Authentication failed. Please contact support.” (This is a developer error.) |
invalid_key | The license key doesn’t exist | ”Invalid license key. Please check and try again.” |
revoked | The license was revoked | ”This license has been deactivated. Contact support.” |
expired | The license has expired | ”Your license has expired. [Renew link]“ |
hwid_mismatch | All HWID slots are full | ”This license is already in use on another device. Contact support to reset.” |
no_credits | App developer ran out of credits | ”Authentication service temporarily unavailable. Please try again later.” |
blocked | HWID or IP is blacklisted | ”Authentication failed. Please contact support.” |
| Network error | No connectivity | ”Could not connect to authentication server. Check your internet connection.” |
Network error retry
On network failures, retry 2–3 times with exponential backoff before giving up:Heartbeat failure handling
The grace period pattern
When a heartbeat fails, start a countdown. Show a non-intrusive warning. If the next heartbeat succeeds, cancel the countdown.Application-specific behavior
| App type | On heartbeat failure |
|---|---|
| Creative tools (editors, DAWs, IDEs) | Auto-save the project. Show a dialog with a “Retry” button. Only close after N consecutive failures. |
| Games | Pause the game and show a modal overlay. Don’t close to desktop. |
| CLI / batch tools | Log the failure. Continue current operation. Exit after it completes if still failing. |
| Services / daemons | Log with severity. Continue running through transient failures. Only shut down after sustained failure. |
Always save before terminating
The onFailure callback pattern
Every SDK language follows the same pattern. Your callback receives a reason string and an optional exception:
Offline and poor connectivity
When to use LOCAL heartbeat mode
LOCAL mode is designed for applications where users may not always have internet access:- The initial
login()call always requires network — make this clear in your app’s system requirements. - After login, LOCAL mode verifies the stored signature locally without network calls.
- When the prepaid session block expires (~25 hours), the SDK makes a new validate call to refresh.
- Revocations don’t take effect until the prepaid block expires and the next validate call.
SERVER mode tolerance
Even in SERVER mode, individual heartbeat failures don’t immediately trigger shutdown (the SDK handles this internally). The failure callback fires when the SDK determines the session is truly invalid — not on every transient network blip. First launch always requires network. Document this in your app’s requirements.Multi-instance and multi-window
If your app can be opened multiple times on the same machine:- Only one instance should authenticate. Use a lockfile or IPC mechanism to coordinate.
- All instances share the same HWID, so extra instances won’t consume HWID slots.
- Each
login()call consumes a credit. If your app opens 10 windows, don’t call login 10 times.
Version updates
- The same license keys work across all versions of your app. You don’t need to regenerate keys when pushing an update.
- Use app variables to enforce a minimum version:
Anti-tampering tips
Protect your App Secret
Don’t log the app secret anywhere. Don’t store it in plain text in the binary. Use environment variables or encrypted configuration.
Authenticate early
Call
login() early in your app’s startup, not lazily. Don’t let the app run unprotected code paths before authentication.Minimize error details
Don’t expose internal auth failure details to the user. “The HMAC check failed” helps attackers — just say “Authentication failed.”
Don't trust the client
Assume the binary can be modified. Critical business logic that depends on license status should check variables, not just a boolean flag.