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.
Requirements
- .NET 6.0 or later
BouncyCastle.Cryptography (pulled in transitively with the AuthForge package)
Installation
Add the AuthForge package from NuGet:
dotnet add package AuthForge
Prefer a source-only layout? Copy AuthForgeClient.cs from GitHub and reference BouncyCastle.Cryptography explicitly. The NuGet package is recommended for most apps.
Quick start
using AuthForge;
var client = new AuthForgeClient(
appId: "YOUR_APP_ID",
appSecret: "YOUR_APP_SECRET",
publicKey: "YOUR_PUBLIC_KEY",
heartbeatMode: "SERVER"
);
Console.Write("Enter license key: ");
var key = Console.ReadLine() ?? "";
if (client.Login(key))
{
Console.WriteLine("Authenticated!");
// Your app logic here; heartbeats run in the background
}
else
{
Console.WriteLine("Invalid license key.");
Environment.Exit(1);
}
Constructor parameters
var client = new AuthForgeClient(
appId: "...", // Required; from dashboard
appSecret: "...", // Required; from dashboard
publicKey: "YOUR_PUBLIC_KEY", // Required; Ed25519 public key from your AuthForge dashboard (base64)
heartbeatMode: "SERVER", // Required; "SERVER" or "LOCAL"
heartbeatInterval: 900, // Optional; seconds (default: 900, any value ≥ 1 is supported)
apiBaseUrl: "https://auth.authforge.cc", // Optional
onFailure: null, // Optional; Action<string, Exception?>
requestTimeout: 15, // Optional; HTTP timeout in seconds
ttlSeconds: null, // Optional; requested session TTL. null = server default (24h). Clamped to [3600, 604800].
hwidOverride: null // Optional; custom identity (for example "tg:123456789")
);
ttlSeconds
Requested session token lifetime in seconds for /auth/validate. 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 so long-running apps in LOCAL mode can extend their offline window up to 7 days.
Billing
- Each successful
Login() or ValidateLicense() costs 1 credit (one /auth/validate debit).
- Heartbeats cost 1 credit per 10 successful calls (billed on every 10th heartbeat). Any
heartbeatInterval ≥ 1 is economically safe.
- Revocations take effect on the next heartbeat regardless of interval.
Login
bool success = client.Login(licenseKey);
Returns true if authentication succeeded, false otherwise. On success, the SDK starts a background heartbeat thread automatically.
Validate license (no heartbeat)
var result = client.ValidateLicense(licenseKey);
if (result.Valid) {
Console.WriteLine(result.SessionToken);
} else {
Console.WriteLine(result.ErrorCode);
}
Same /auth/validate request and verification as Login, without updating the client’s session fields or starting the heartbeat thread.
Failure callback
If authentication or a heartbeat fails, the SDK calls your OnFailure callback. If no callback is set (or the callback throws), the SDK calls Environment.Exit(1).
void HandleFailure(string reason, Exception? exception)
{
if (reason == "login_failed")
{
Console.WriteLine("Login failed; check your license key.");
}
else if (reason == "heartbeat_failed")
{
Console.WriteLine("Heartbeat failed; saving state.");
SaveApplicationState();
}
}
var client = new AuthForgeClient(
appId: "YOUR_APP_ID",
appSecret: "YOUR_APP_SECRET",
publicKey: "YOUR_PUBLIC_KEY",
heartbeatMode: "SERVER",
onFailure: HandleFailure
);
If you don’t set onFailure, the SDK terminates the process immediately on any failure. Always set a callback in production to handle graceful shutdown.
Reading variables
After a successful login, app variables and license variables are available:
if (client.Login(licenseKey))
{
// App-wide variables
var appVars = client.AppVariables;
if (appVars.TryGetValue("maintenanceMode", out var maintenance) && maintenance is true)
{
Console.WriteLine("Server is under maintenance.");
Environment.Exit(0);
}
// Per-license variables
var plan = client.LicenseVariables.GetValueOrDefault("plan", "basic");
if (plan?.ToString() == "pro")
{
EnableProFeatures();
}
}
Heartbeat modes
// SERVER mode; pings the API every interval
var client = new AuthForgeClient(
appId: "...",
appSecret: "...",
publicKey: "YOUR_PUBLIC_KEY",
heartbeatMode: "SERVER",
heartbeatInterval: 900
);
// LOCAL mode; verifies locally, re-validates when the session token expires (default 24h; up to 7d via ttlSeconds)
var client = new AuthForgeClient(
appId: "...",
appSecret: "...",
publicKey: "YOUR_PUBLIC_KEY",
heartbeatMode: "LOCAL",
heartbeatInterval: 900
);
See Heartbeat Modes for a detailed comparison.
Full example (WPF)
using System.Windows;
using AuthForge;
public partial class App : Application
{
private AuthForgeClient? _authClient;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
_authClient = new AuthForgeClient(
appId: "YOUR_APP_ID",
appSecret: "YOUR_APP_SECRET",
publicKey: "YOUR_PUBLIC_KEY",
heartbeatMode: "SERVER",
onFailure: OnAuthFailure
);
var dialog = new LicenseDialog();
if (dialog.ShowDialog() != true)
{
Shutdown();
return;
}
if (!_authClient.Login(dialog.LicenseKey))
{
MessageBox.Show("Invalid license key.", "Authentication Failed",
MessageBoxButton.OK, MessageBoxImage.Error);
Shutdown();
return;
}
var mainWindow = new MainWindow();
mainWindow.Show();
}
private void OnAuthFailure(string reason, Exception? ex)
{
Dispatcher.Invoke(() =>
{
// Save user's work before shutting down
(MainWindow as MainWindow)?.SaveState();
MessageBox.Show(
"License verification failed. Your work has been saved.",
"Authentication Error",
MessageBoxButton.OK,
MessageBoxImage.Warning
);
Shutdown();
});
}
}
GitHub
Full source, changelog, and issues: AuthForgeCC/authforge-csharp