You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The grace period (running on the signed session until the TTL expires) is now the default and needs no configuration. Online check-ins are opt-in via online_heartbeat=True. Legacy heartbeat mode values still work behind a deprecation shim: LOCAL maps to the default, SERVER maps to online check-ins. README and AGENTS rewritten with the new vocabulary and a migration section. Version bumped to 1.1.0.
Copy file name to clipboardExpand all lines: AGENTS.md
+35-20Lines changed: 35 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,21 +1,21 @@
1
-
# AuthForge SDK — AI Agent Reference
1
+
# AuthForge SDK: AI Agent Reference
2
2
3
3
> This file is optimized for AI coding agents (Cursor, Copilot, Claude Code, etc.).
4
4
> It contains everything needed to correctly integrate AuthForge licensing into a project.
5
5
6
6
## What AuthForge does
7
7
8
-
AuthForge is a license key validation service. Your app sends a license key + hardware ID to the AuthForge API, gets back a cryptographically signed response, and runs background heartbeats to maintain the session. If the license is revoked or expired, the heartbeat fails and you handle it (typically exit the app).
8
+
AuthForge is a license key validation service. Your app activates by sending a license key + hardware ID to `POST /auth/validate`; the server checks revocation, expiry, HWID binding, and credits, then returns an Ed25519-signed session with a TTL. By default the app then runs through the **grace period**: it keeps running on the signed session with no network calls, and a background check fails when the session TTL expires. Optionally, enable **online check-ins** (`online_heartbeat=True`): periodic `POST /auth/heartbeat` calls for fast revocation and concurrent-use detection. If the license is revoked or expired, the check-in fails and you handle it (typically exit the app).
9
9
10
10
## Billing model (so you can pick sensible intervals)
-**10 heartbeats = 1 credit** (billed on every 10th successful heartbeat per license).
14
-
- Keep `heartbeat_interval` at `>= 10` seconds (`900` / 15 min is the typical desktop default). `/auth/heartbeat` is limited to 6 requests/minute per license key, and revocations still take effect on the **next**heartbeat.
13
+
-**10 online check-ins = 1 credit** (billed on every 10th successful `/auth/heartbeat` per license). Grace period checks are local and free.
14
+
- Keep `heartbeat_interval` at `>= 10` seconds (`900` / 15 min is the typical desktop default). `/auth/heartbeat` is limited to 6 requests/minute per license key, and revocations still take effect on the **next**check-in.
15
15
16
16
## Installation
17
17
18
-
Prefer **`pip install authforge-sdk`** from [PyPI](https://pypi.org/project/authforge-sdk/) (installs the `cryptography` dependency). Imports remain **`from authforge import …`**. For a vendored single-file layout, copy `authforge.py` and add `cryptography` to your environment. Requires Python 3.9+.
18
+
Prefer **`pip install authforge-sdk`** from [PyPI](https://pypi.org/project/authforge-sdk/) (installs the `cryptography` dependency). Imports remain **`from authforge import ...`**. For a vendored single-file layout, copy `authforge.py` and add `cryptography` to your environment. Requires Python 3.9+.
19
19
20
20
## Minimal working integration
21
21
@@ -37,7 +37,7 @@ def main() -> None:
37
37
client = AuthForgeClient(
38
38
app_id="YOUR_APP_ID",
39
39
app_secret="YOUR_APP_SECRET",
40
-
heartbeat_mode="SERVER",
40
+
public_key="YOUR_PUBLIC_KEY", # required: base64 Ed25519 key from the dashboard
41
41
on_failure=on_failure,
42
42
)
43
43
license_key =input("Enter license key: ").strip()
@@ -54,40 +54,55 @@ if __name__ == "__main__":
54
54
main()
55
55
```
56
56
57
+
This activates once and then runs through the grace period (no network) until the session TTL expires. To detect revocations quickly or catch concurrent use, add `online_heartbeat=True` (and optionally tune `heartbeat_interval`).
|`public_key`|`str \| Sequence[str]`| yes | n/a | Base64 Ed25519 public key from the dashboard. Accepts one key, a list, or a comma-separated string; the SDK trusts a signature matching **any** entry (key rotation) |
66
+
|`heartbeat_mode`|`str \| None`| no |`None`| Deprecated shim: `"LOCAL"` maps to the default (grace period), `"SERVER"` maps to `online_heartbeat=True`. Emits a `DeprecationWarning` when provided (case-insensitive) |
67
+
|`heartbeat_interval`|`int`| no |`900`| Seconds between background checks (minimum `10`); applies to grace period checks and online check-ins |
65
68
|`api_base_url`|`str`| no |`https://auth.authforge.cc`| API base URL |
66
-
|`on_failure`|`Callable[[str, Optional[Exception]], None] \| None`| no |`None`| Called on login/heartbeat/network failure; if omitted, process exits via `os._exit(1)` (not used by `validate_license`) |
69
+
|`on_failure`|`Callable[[str, Optional[Exception]], None] \| None`| no |`None`| Called on activation/check-in/network failure; if omitted, process exits via `os._exit(1)` (not used by `validate_license`) |
67
70
|`request_timeout`|`int`| no |`15`| HTTP timeout (seconds) |
68
-
|`ttl_seconds`|`int \| None`| no |`None` (server default: 86400) |Requested session token lifetime. Server clamps to `[3600, 604800]`; preserved across heartbeat refreshes. |
71
+
|`ttl_seconds`|`int \| None`| no |`None` (server default: 86400) |The grace period duration: how long the app keeps running on the signed session without contacting AuthForge. Server clamps to `[3600, 604800]` (1h to 7d); preserved across check-in refreshes. |
69
72
|`hwid_override`|`str \| None`| no |`None`| Optional custom HWID/subject string. When set to a non-empty value (for example `tg:123456789`), the SDK sends it instead of generating a machine fingerprint. |
73
+
|`online_heartbeat`|`bool` (keyword-only) | no |`False`| Enable online check-ins: periodic `POST /auth/heartbeat` for fast revocation and concurrent-use detection |
70
74
71
75
For Telegram/Discord bot flows, prefer immutable IDs (`tg:<user_id>`, `discord:<user_id>`) instead of usernames.
72
76
77
+
## Migrating from heartbeat_mode
78
+
79
+
Earlier releases required `heartbeat_mode="LOCAL"` or `"SERVER"` as the 4th argument. It is now optional and deprecated (still accepted, but emits a `DeprecationWarning`):
80
+
81
+
-`heartbeat_mode="LOCAL"`: remove the argument; the grace period is the default.
82
+
-`heartbeat_mode="SERVER"`: replace with `online_heartbeat=True`.
83
+
84
+
The attribute `client.heartbeat_mode` still exists for back-compat and reflects the effective policy (`"SERVER"` when online check-ins are enabled, `"LOCAL"` otherwise).
|`validate_license(license_key: str)`|`ValidateLicenseResult`| Same validate + signatures as login; no session persistence or heartbeat; **never** calls `on_failure` or `os._exit`|
79
-
|`logout()`|`None`| Stops heartbeat and clears session state |
90
+
|`login(license_key: str)`|`bool`|Activates: validates the license online, verifies signatures, starts the background check thread |
91
+
|`validate_license(license_key: str)`|`ValidateLicenseResult`| Same validate + signatures as login; no session persistence or background checks; **never** calls `on_failure` or `os._exit`|
92
+
|`logout()`|`None`| Stops background checks and clears session state |
80
93
|`is_authenticated()`|`bool`| Whether a session token is present and marked authenticated |
81
94
|`get_session_data()`|`dict \| None`| Decoded signed payload map |
Full set (`KNOWN_SERVER_ERRORS`): invalid_app, invalid_key, expired, revoked, hwid_mismatch, no_credits, app_burn_cap_reached, blocked, rate_limited, replay_detected, app_disabled, session_expired, revoke_requires_session, bad_request, malformed_request, system_error
88
101
89
102
Notes:
90
103
-`replay_detected` is validate-only. `rate_limited` can be returned by `/auth/validate` and `/auth/heartbeat` (heartbeat is license-limited at 6/min and has no app-layer IP limit).
104
+
-`app_burn_cap_reached` means the app's configured credit burn cap is hit; `revoke_requires_session` means a pre-session self-ban tried to revoke a license (only session-authenticated self-ban can revoke).
105
+
-`session_expired` is also raised locally when the grace period (session TTL) runs out.
- Do not hardcode the app secret as a plain string literal in source — use environment variables or encrypted config
126
-
- Do not skip the `on_failure` callback — without it, heartbeat failures terminate the process via `os._exit(1)` without your cleanup
127
-
- Do not call `login()` on every app action — call it once at startup; heartbeats handle the rest
128
-
- Do not use`heartbeat_mode="LOCAL"` unless the app has no internet after initial auth
140
+
- Do not hardcode the app secret as a plain string literal in source: use environment variables or encrypted config
141
+
- Do not skip the `on_failure` callback: without it, background check failures terminate the process via `os._exit(1)` without your cleanup
142
+
- Do not call `login()` on every app action: call it once at startup; the grace period (or online check-ins) handles the rest
143
+
- Do not pass`heartbeat_mode` in new code: it is deprecated. Use the default grace period, or `online_heartbeat=True` when you need fast revocation or concurrent-use detection
0 commit comments