> ## Documentation Index
> Fetch the complete documentation index at: https://docs.authforge.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK Overview

> Install the official AuthForge SDK for Python, C#, C++, Rust, Go, or Node.js from package managers and registries.

The AuthForge SDK handles license validation, HWID fingerprinting, cryptographic signature verification, the grace period, and optional online check-ins.

## Available SDKs

<CardGroup cols={3}>
  <Card title="Python SDK" icon="python" href="/sdk/python">
    **`authforge-sdk`** on PyPI

    Python 3.9+; `cryptography` pulled in automatically.
  </Card>

  <Card title="C# SDK" icon="microsoft" href="/sdk/csharp">
    **`AuthForge`** on NuGet

    .NET 6+ with `BouncyCastle.Cryptography`.
  </Card>

  <Card title="C++ SDK" icon="c" href="/sdk/cpp">
    **CMake library** from GitHub

    C++17, libsodium, OpenSSL, libcurl.
  </Card>

  <Card title="Rust SDK" icon="code" href="/sdk/rust">
    **`authforge`** on crates.io

    Rust 1.70+, blocking HTTP via `ureq`.
  </Card>

  <Card title="Go SDK" icon="go" href="/sdk/go">
    **`github.com/AuthForgeCC/authforge-go`**

    Go 1.21+, standard library only.
  </Card>

  <Card title="Node.js SDK" icon="node-js" href="/sdk/node">
    **`@authforgecc/sdk`** on npm

    Node.js 18+, zero runtime dependencies.
  </Card>
</CardGroup>

## Official installs

| SDK | Install command | Registry / source |
| - | - | - |
| Python | `pip install authforge-sdk` | [PyPI; authforge-sdk](https://pypi.org/project/authforge-sdk/) |
| C# | `dotnet add package AuthForge` | [NuGet; AuthForge](https://www.nuget.org/packages/AuthForge/) |
| Rust | `cargo add authforge` | [crates.io; authforge](https://crates.io/crates/authforge) |
| Node.js | `npm install @authforgecc/sdk` | [npm; @authforgecc/sdk](https://www.npmjs.com/package/@authforgecc/sdk) |
| Go | `go get github.com/AuthForgeCC/authforge-go@vX.Y.Z` | [GitHub; authforge-go](https://github.com/AuthForgeCC/authforge-go) (module path; pin a release tag) |
| C++ | CMake: clone / release tarball, or `FetchContent` from GitHub | [GitHub; authforge-cpp](https://github.com/AuthForgeCC/authforge-cpp) (no C++ registry: build from source) |

## How it works

All SDKs implement the same flow:

1. **Initialize**: Create a client with your App ID and public key. Include the App Secret for online `login()` / `validateLicense`. For air-gapped `loginFromFile` only, omit the secret (or pass empty / `None`); do not ship it in offline binaries.
2. **Login or validate-only**: Call `login(licenseKey)` (or `Login`, etc.) for a long-lived session: the SDK collects the machine's HWID (or uses `hwidOverride`), generates a nonce, and sends `/auth/validate`. For **bots, cron, or per-request checks**, use the validate-only API (**`validateLicense`** in Node, **`validate_license`** in Python and Rust, **`ValidateLicense`** in C# / C++ / Go): same request and signature verification, **no background loop** and **no persisted session** on the client (C++ returns a result struct; others match their `login` result shape or a dedicated result type).
3. **Verify the validate response**: The SDK verifies the Ed25519 signature on `/auth/validate` using your app's configured `publicKey`.
4. **Grace period**: After `login`, the app runs on the signed session with no further network calls. A background thread re-verifies the session signature locally and stops when the session expires (session TTL: default 24 hours, configurable via `ttlSeconds`, clamped to 1 hour minimum and 7 days maximum). Expiry is reported to `onFailure` as `session_expired`; the Rust SDK reports it as `AuthForgeError::Expired` (`expired`) until its next major release.
5. **Online check-ins (optional)**: Enable `onlineHeartbeat` to send `POST /auth/heartbeat` at the configured interval (default 15 minutes) for fast revocation and concurrent-use detection. Success responses are Ed25519-signed and verified with the same app public key, and each check-in refreshes the session. Validate-only calls never start this loop.
6. **Failure**: If authentication fails, a check-in fails, or the session expires, the SDK calls your `onFailure` callback with a reason (`"login_failed"` or `"heartbeat_failed"`) and the exception (Go: `OnHeartbeatFailure` or legacy `OnFailure`; Rust: `on_heartbeat_failure` or legacy `on_failure`). Since 1.4.0 the error carries the code and a transient/definitive classification. On a **definitive** failure (`revoked`, `expired`, `hwid_mismatch`, `blocked`, `session_expired`, ...) the SDK clears the stored session and stops check-ins before the callback runs; on a **transient** one (network errors, `rate_limited`, `system_error`, `no_credits`, `unexpected_response`, ...) it keeps the session and checks in again on the next interval, until the session TTL runs out. If no callback is set (1.4.1+), a transient background check failure writes a one-line warning to stderr and check-ins continue in every SDK; a definitive failure (including the `session_expired` a transient failure becomes once the TTL has passed) or a rejected login exits the process in the Python, Node.js, C#, and C++ SDKs, while Go and Rust clear the session and never exit. See [Check-in and session failure handling](/sdk/best-practices#check-in-and-session-failure-handling).

### Offline license files (separate mode)

For machines that can **never** reach AuthForge, every SDK (1.2.0+) also verifies cloud-minted [offline license files](/features/offline-license-files) (`.authforge`) with zero network access. This is not a variant of the grace period; it is a different credential:

| | Python | Node.js | Go | Rust | C# | C++ |
| - | - | - | - | - | - | - |
| Authorize from file | `login_from_file(path_or_text)` | `loginFromFile(pathOrText)` | `LoginFromFile(pathOrText)` | `login_from_file(path_or_text)` | `LoginFromFile(pathOrText)` | `LoginFromFile(pathOrText)` |
| Pure verify | `verify_license_file(...)` | `verifyLicenseFile(...)` | `VerifyLicenseFile(...)` | `verify_license_file(...)` | `VerifyLicenseFile(...)` | `VerifyLicenseFile(...)` |
| Machine ID for binding | `get_hwid()` | `getHwid()` | `HWID()` | `hwid()` | `GetHwid()` | `GetHwid()` |
| Write activation request | `write_activation_request(path)` | `writeActivationRequest(path)` | `CreateActivationRequest(opts)` | `create_activation_request(opts)` | `CreateActivationRequest(opts)` | `CreateActivationRequest(opts)` |
| File in use | `get_offline_license()` | `getOfflineLicense()` | `OfflineLicense()` | `get_offline_license()` | `GetOfflineLicense()` | `GetOfflineLicense()` |

The customer should not type the HWID into an email. Prefer an [activation request](/guides/activation-requests) (`.authforge-request`): the SDK writes it with no network and no app secret, and the dashboard checksums it in the browser before prefilling the mint dialog. `machineName` is omitted unless the caller opts in (`include_machine_name` / `includeMachineName`). This is not a second offline product and it is not the grace period.

`loginFromFile` verifies the file against the client's configured app id, public key(s) and HWID, then populates the same session accessors as `login()` (`isAuthenticated`, variables). It never starts the grace-period timer or online check-ins, and it never exits the process; rejections arrive as `onFailure("offline_login_failed", error)` with one of `bad_armor`, `bad_signature`, `unsupported_version`, `malformed_payload`, `wrong_app`, `expired`, `hwid_mismatch` (Go returns `ErrOffline*` sentinels, Rust an `OfflineLicenseError` enum). Online `login()` and the grace period are unchanged. **Air-gapped builds should omit the App Secret**: `loginFromFile` does not use it; online APIs still require it and fail locally if it is missing.

## Common constructor parameters

Every SDK accepts the same conceptual parameters, named according to each language's conventions. The table below shows the logical parameter names; see each SDK's page for exact syntax.

| Parameter | Type | Default | Description |
| - | - | - | - |
| `appId` | string | required | Your application ID from the dashboard |
| `appSecret` | string | required for online APIs; omit / empty for `loginFromFile` only | Your application secret. Authenticates `/auth/validate` and other online calls. **Do not ship it in air-gapped binaries** — offline file verification uses only the app id and public key. |
| `publicKey` | string | required | Your app Ed25519 public key (base64) |
| `onlineHeartbeat` | boolean | `false` | Enable periodic online check-ins (`/auth/heartbeat`) for fast revocation. Off by default: the app runs through the grace period on the signed session. |
| `heartbeatInterval` | integer | `900` | Seconds between background timer ticks. With `onlineHeartbeat` enabled each tick calls `/auth/heartbeat` (server rate limit: 6 per minute per license); otherwise each tick re-verifies the signed session locally and enforces grace period expiry, with no network. |
| `apiBaseUrl` | string | `https://auth.authforge.cc` | Override the API base URL |
| `onFailure` | callback | `null` | Called on auth failure, check-in failure, or session expiry with `(reason, exception)`. Check-in errors carry the code and a transient/definitive classification (1.4.0+). Go and Rust also offer a typed `OnHeartbeatFailure` / `on_heartbeat_failure` |
| `requestTimeout` | integer | `15` | HTTP request timeout in seconds |
| `ttlSeconds` | integer | `null` / `0` (server default: 86400) | Requested session token lifetime, which is the grace period. Server clamps to `[3600, 604800]` (1 hour to 7 days). Preserved across heartbeat refreshes. |
| `heartbeatMode` | string | deprecated | Legacy option: `"LOCAL"` maps to the default (grace period), `"SERVER"` maps to `onlineHeartbeat: true`. Still accepted, but new code should not use it. |

## Billing model

All SDKs follow the same billing rules:

* Each successful `login()` / `Login()` or **`validateLicense`**-style call costs **1 credit** (one `/auth/validate` debit).
* The grace period is free: local session re-verification consumes no credits.
* Online check-ins (if enabled) cost **1 credit per 10 successful heartbeats** (debited on every 10th heartbeat).
* With online check-ins, revocations take effect on the **next** check-in regardless of the configured interval; without them, at session expiry.
* Minting an offline license file costs **1 credit** (charged to the operator at mint time). `loginFromFile` / `verifyLicenseFile` cost nothing.

See [Managing Credits](/best-practices/credit-management) for usage estimates and cost-saving patterns.

## Migrating from `heartbeat_mode`

Older SDK versions required a `heartbeatMode` / `heartbeat_mode` of `"SERVER"` or `"LOCAL"`. Cached GitHub README snippets still show that required constructor; current docs and current SDKs use the grace-period model. Follow [docs.authforge.cc](https://docs.authforge.cc) and check the installed SDK version before copying examples.

The option is deprecated across all SDKs:

* **`"LOCAL"`**: remove the option; the grace period is now the default behavior.
* **`"SERVER"`**: enable online check-ins instead (`onlineHeartbeat: true` or the language equivalent).

The old option still works but emits a deprecation warning. See each SDK page for the exact migration syntax. Do not pass `heartbeatMode` in new code.

## Next steps

* Choose your SDK: [Python](/sdk/python), [C#](/sdk/csharp), [C++](/sdk/cpp), [Rust](/sdk/rust), [Go](/sdk/go), or [Node.js](/sdk/node)
* Read the [SDK Best Practices](/sdk/best-practices) for error handling, grace-period behavior, and UX guidance


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.