Skip to main content

Requirements

  • .NET 6.0 or later
  • BouncyCastle.Cryptography (pulled in transitively with the AuthForge package)

Installation

Add the AuthForge package from NuGet:
Prefer a source-only layout? Copy AuthForgeClient.cs, AuthForgeClient.Offline.cs, and AuthForgeException.cs from GitHub and reference BouncyCastle.Cryptography explicitly. The NuGet package is recommended for most apps.

Quick start

Constructor parameters

ttlSeconds (grace period)

Requested session token lifetime in seconds for /auth/validate. This is the grace period: how long the app keeps running on the signed session without contacting AuthForge. Pass null (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() or ValidateLicense() costs 1 credit (one /auth/validate debit).
  • 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

Returns true if authentication succeeded, false otherwise. On success, the SDK starts a background thread that re-verifies the signed session locally during the grace period (and sends online check-ins if onlineHeartbeat: true).

Validate license (no session)

Same /auth/validate request and verification as Login, without updating the client’s session fields or starting the background thread.

Failure callback

If authentication fails, an online check-in fails, or the session expires, the SDK calls your OnFailure callback. Returning normally from the callback keeps the process running; if the callback throws, the SDK calls Environment.Exit(1). Without a callback (1.4.1+), a transient background check failure writes AuthForge: background check failed (<code>); retrying next interval to stderr and check-ins continue; every other failure (a rejected Login, a definitive check-in answer, the grace period running out) calls Environment.Exit(1).

Check-in failures (1.4.0+)

Background check failures (online check-ins and the end of the grace period) reach onFailure("heartbeat_failed", ex), where ex is an AuthForgeException:
  • ex.Code: the server’s error code from the response body, whatever the HTTP status, or an SDK code: network_error, timeout, http_error_<status> (non-JSON error body), invalid_json_response, unexpected_response, signature_mismatch, nonce_mismatch, … For server codes ex.Message equals the code; network failures keep the url_error: ... message. Codes this SDK version doesn’t know are passed through unchanged.
  • ex.IsTransient / ex.IsFatal: the classification. AuthForgeClient.IsTransientError(code) is the same check, and AuthForgeClient.DefinitiveErrorCodes lists the fatal codes.
unexpected_response means a failed check-in body was not a well-formed AuthForge error ({"status":"failed","error":"<code>"}), for example a proxy or captive portal answering instead of AuthForge; the message includes the raw status and error values. Request retries are automatic: rate_limited (or HTTP 429 with no error code) is retried after 2s, then 5s; HTTP 429 with no_credits, app_burn_cap_reached, or demo_quota_exceeded is not retried and waits for the next interval; a network failure is retried once after 2s. Heartbeat network failures are reported once, as heartbeat_failed with code network_error or timeout. Thread safety: onFailure for heartbeat_failed runs on the background thread with no SDK lock held. Calling Logout(), IsAuthenticated(), or Login() from it is safe; Logout() signals the thread to stop and never waits for it. A check-in response that arrives after Logout() or a new Login() is discarded, so it cannot restore the old session. 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:
In a WinForms or WPF app, marshal to the UI thread instead (form.BeginInvoke(...) or Dispatcher.InvokeAsync(...)) and close the main window normally, as in the full example. Calling Environment.Exit(1) inside onFailure is a last resort: finally blocks on other threads do not run and unsaved state is lost, so save the user’s work first.
If you don’t set onFailure, a rejected login or a definitive background failure (including session_expired once the grace period runs out) terminates the process immediately with Environment.Exit(1), with no chance to save. Transient check-in failures only print a warning to stderr. Always set a callback in production to handle graceful shutdown.

Reading variables

After a successful login, app variables and license variables are available:

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:
See Online Check-ins for a detailed comparison.

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 appSecret: "" so the air-gapped binary does not contain the App Secret.
Failures call onFailure("offline_login_failed", new ArgumentException(code)) and return false (never Environment.Exit). Codes, in check order: bad_armor, bad_signature, unsupported_version, malformed_payload, wrong_app, expired, hwid_mismatch. client.VerifyLicenseFile(pathOrText) and the static AuthForgeClient.VerifyLicenseFile(text, appId, publicKeys, hwid) run the same checks without touching state. 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 heartbeatMode

The legacy string heartbeatMode constructor is marked obsolete but still works:
  • heartbeatMode: "LOCAL": remove the argument; the grace period is now the default.
  • heartbeatMode: "SERVER": use onlineHeartbeat: true instead.

Full example (WPF)

GitHub

Full source, changelog, and issues: AuthForgeCC/authforge-csharp