This walkthrough is for machines that never reach AuthForge. It is a separate mode from the grace period. If the customer’s machine can connect even occasionally, use online login() instead.
1. Mint in the dashboard
- Open the license (Applications → app → Licenses → license page) and click Mint .authforge file.
- Pick an expiry. The file cannot outlive the license. Lifetime is only available for perpetual licenses.
- Bind the file to the customer’s HWID (recommended). Prefer an activation request (
.authforge-request) the SDK wrote on the machine over a pasted HWID string — the dashboard checksums the file so email damage cannot silently mint to the wrong id. Collect it from the same SDK language that will callloginFromFile— fingerprints are not portable across SDKs. - Click Mint & download. 1 credit is charged. The file body is never stored server-side, so download it now.
The Developer API equivalent is POST /v1/licenses/{licenseKey}/offline-files with scope write:licenses.
2. Ship the file and the public key
The verifying machine needs three things and nothing else:
- the
.authforgefile - your app id
- your app’s Ed25519 public key
Do not embed the App Secret in air-gapped binaries. Offline verification does not use it.
Put the file next to the installer (or behind a USB / data-diode copy step) and embed the public key the same way you already do for online login(). Copy it from Application settings in the dashboard.
3. Verify on the air-gapped machine
Call the SDK’s file-verify entry point at launch. It never starts the grace-period timer or online check-ins, and it never exits the process on its own.
from authforge import AuthForgeClient
# Valid until the file's own expiresAt; cannot be remotely revoked.
client = AuthForgeClient(
app_id="YOUR_APP_ID",
app_secret=None,
public_key="YOUR_PUBLIC_KEY",
)
print("HWID:", client.get_hwid()) # send this to the vendor before they mint
if not client.login_from_file("license.authforge"):
raise SystemExit("Offline license file rejected") import { AuthForgeClient } from "@authforgecc/sdk";
// Valid until the file's own expiresAt; cannot be remotely revoked.
const client = new AuthForgeClient({
appId: "YOUR_APP_ID",
publicKey: "YOUR_PUBLIC_KEY",
});
console.log("HWID:", client.getHwid());
if (!client.loginFromFile("./license.authforge")) {
console.error("Offline license file rejected.");
process.exit(1);
} client, err := authforge.New(authforge.Config{
AppID: "YOUR_APP_ID",
PublicKey: "YOUR_PUBLIC_KEY",
})
if err != nil {
panic(err)
}
fmt.Println("HWID:", client.HWID())
if _, err := client.LoginFromFile("license.authforge"); err != nil {
panic(err)
} var client = new AuthForgeClient(
appId: "YOUR_APP_ID",
appSecret: "",
publicKey: "YOUR_PUBLIC_KEY"
);
Console.WriteLine($"HWID: {client.GetHwid()}");
if (!client.LoginFromFile("license.authforge"))
{
throw new Exception("Offline license file rejected");
} Rejection codes, in check order: bad_armor, bad_signature, unsupported_version, malformed_payload, wrong_app, expired, hwid_mismatch.
4. Re-issue before expiry
Treat re-issuing as your revocation lever.
- Surface
expiresAtafter a successfulloginFromFile(About / License screen). - Warn the customer at 14 days and again at 3 days.
- Mint a new file with the same HWID policy, deliver it out-of-band, and have them replace the old file.
- Stop re-issuing when the entitlement should end; the outstanding file lapses on its own clock.
Minting costs 1 credit. Verifying the file on the machine is free.
Next steps
- Offline license files — format, verify order, mint API
- Offline licensing best practices
- SDK index — install commands for all six languages
- Offline licensing — product overview