Skip to main content

AuthForge Python SDK

Official Python SDK for AuthForge: credit-based license key authentication with Ed25519-verified responses.

Uses cryptography for Ed25519 verification. Works on Python 3.9+.

How licensing works

  1. Activate online. login() calls POST /auth/validate. The server checks revocation, expiry, HWID binding, and credits, then returns an Ed25519-signed session with a TTL.
  2. Run through the grace period. By default the app keeps running on the signed session with no further network calls. A background check re-verifies the signature locally and fails when the session TTL expires. The grace period equals the session TTL: default 24h, and the server clamps requested values to 1h to 7d.
  3. Optionally enable online check-ins. With online_heartbeat=True, the SDK also calls POST /auth/heartbeat every heartbeat_interval seconds for fast revocation and concurrent-use detection.

Separately, for machines that can never reach the internet, an operator can mint a signed offline license file (.authforge) in the AuthForge dashboard or Developer API. The SDK verifies it locally with your app public key: see Offline license files. If the machine can go online once, the end user can get that file themselves with activate_offline(): see Self-serve offline activation.

Features

Everything in this list ships in authforge.py today:

  • License validation via POST /auth/validate, returning a signed session payload.
  • Ed25519 signature verification on every /auth/validate and /auth/heartbeat response; tampered or unsigned responses are rejected.
  • Key rotation: public_key accepts a single key, a list of keys, or a comma-separated string. The SDK trusts a signature that matches any key in the list, so you can roll the server-side signing key without breaking deployed clients.
  • Grace period by default: after one successful activation, the app runs on the signed session (no network) until the TTL expires.
  • Online check-ins (opt-in): periodic /auth/heartbeat calls for fast revocation and concurrent-use detection.
  • Offline license files (.authforge): login_from_file() / verify_license_file() verify a cloud-minted, Ed25519-signed file with zero network access for air-gapped machines.
  • Self-serve offline activation: activate_offline() turns a license key into a lifetime, HWID-bound .authforge file with one online call, then runs offline from that file.
  • Nonce anti-replay: a fresh 128-bit nonce is sent on every request and the echoed nonce in the signed payload is checked before the response is accepted.
  • HWID fingerprinting: deterministic device hash from MAC + CPU + disk serial, with graceful per-component fallback.
  • hwid_override: bind to any identity instead of the machine (for example tg:<id>, discord:<id>).
  • Seat enforcement: the server binds each HWID into a license's free slots up to maxHwidSlots; hwid_count / max_hwid_slots are surfaced on the result. A shared (unlimited-seat) key skips per-device binding.
  • Self-ban (self_ban()) for anti-tamper response, both pre-session and post-session.
  • Grace period duration control via ttl_seconds, with server-side clamping to [3600, 604800].
  • App variables / license variables for feature flags and tiered licensing.
  • Automatic retries for rate-limited and transient network failures, with a fresh nonce per retry.

Installation

Install from PyPI as authforge-sdk. In code, import the authforge module:

pip install authforge-sdk

Alternative: copy authforge.py into your project if you need a single-file vendored layout (you must still satisfy the cryptography dependency yourself).

Quick Start

After pip install authforge-sdk (or vendoring authforge.py), use:

from authforge import AuthForgeClient

client = AuthForgeClient(
    app_id="YOUR_APP_ID",           # from your AuthForge dashboard
    app_secret="YOUR_APP_SECRET",   # from your AuthForge dashboard
    public_key="YOUR_PUBLIC_KEY",   # from your AuthForge dashboard
)

license_key = input("Enter license key: ")

if client.login(license_key):
    print("Activated!")
    # Your app logic here. The app runs through the grace period by default:
    # no further network calls until the session TTL expires.
else:
    print("Invalid license key.")
    exit(1)

To detect revocations quickly (or concurrent use), enable online check-ins:

client = AuthForgeClient(
    app_id="YOUR_APP_ID",
    app_secret="YOUR_APP_SECRET",
    public_key="YOUR_PUBLIC_KEY",
    heartbeat_interval=900,   # check in every 15 minutes
    online_heartbeat=True,    # periodic POST /auth/heartbeat
)

Configuration

Parameter Type Default Description
app_id str required Your application ID from the AuthForge dashboard
app_secret str required for online APIs; None / "" for login_from_file only Your application secret from the AuthForge dashboard. Do not ship it in air-gapped binaries.
public_key str | Sequence[str] required App Ed25519 public key(s) (base64) from dashboard. Pass one key, a list of keys, or a comma-separated string to trust multiple keys during rotation (see Key rotation).
heartbeat_mode str | None None Deprecated shim (see Migrating from heartbeat_mode). Use online_heartbeat instead.
heartbeat_interval int 900 Seconds between background checks (minimum 10; default 15 min). Applies to both grace period checks and online check-ins.
api_base_url str https://auth.authforge.cc API endpoint
on_failure callable None Callback `(reason: str, exc: Exception
request_timeout int 15 HTTP request timeout in seconds
ttl_seconds int | None 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.
hwid_override str | None None Optional custom hardware/subject identifier. When set to a non-empty value, the SDK uses it instead of machine fingerprinting.
online_heartbeat bool (keyword-only) False Enable online check-ins: periodic POST /auth/heartbeat for fast revocation and concurrent-use detection.

Identity-based binding example (Telegram/Discord)

client = AuthForgeClient(
    app_id="YOUR_APP_ID",
    app_secret="YOUR_APP_SECRET",
    public_key="YOUR_PUBLIC_KEY",
    hwid_override=f"tg:{telegram_user_id}",  # or f"discord:{discord_user_id}"
)

Key rotation

public_key is a trust list. To rotate the server-side signing key without a flag-day, ship the new key alongside the previous one; the SDK accepts a signature that matches any entry:

client = AuthForgeClient(
    app_id="YOUR_APP_ID",
    app_secret="YOUR_APP_SECRET",
    public_key=["NEW_PUBLIC_KEY", "PREVIOUS_PUBLIC_KEY"],  # or "NEW,PREVIOUS"
)

client.public_keys exposes the full trust list; client.public_key is the first (primary) entry.

Grace period and online check-ins

Grace period (default). After a successful activation, the SDK re-verifies the cached signed session payload and checks the expiry timestamp locally at each heartbeat_interval: no network calls. When the session TTL expires, it triggers failure with session_expired. The grace period is session continuation within the session TTL (default 24h, server clamps 1h to 7d) after one successful online activation. It is not persistent offline licensing, and a mid-session revocation is not picked up until the next online validate or check-in.

Online check-ins (opt-in, online_heartbeat=True). The SDK calls /auth/heartbeat every heartbeat_interval seconds with a fresh nonce, verifies signature + nonce, and triggers failure on invalid session state. Use this when you need fast revocation propagation or concurrent-use detection. A definitive rejection (revoked, hwid_mismatch, blocked, ...) clears the stored session immediately; every other failure (network, rate_limited, system_error, no_credits, unrecognized responses, ...) is transient and keeps it until the session TTL runs out. See Background check failures.

Tune ttl_seconds to set the grace period duration (server default 24h, clamped to 1h to 7d).

Offline license files (.authforge)

For machines that never connect to the internet, the operator mints a signed offline license file in the AuthForge dashboard (License page -> Mint .authforge file) or via POST /v1/licenses/{licenseKey}/offline-files. The file is a standalone Ed25519-signed document; the SDK verifies it with only your app public key and the machine HWID. It never contacts AuthForge and never starts online check-ins. Pass app_secret=None (or "") so the air-gapped binary does not contain the App Secret.

Grace period (default) Offline license file
Needs network Once, at login() Never on the end machine
What is verified Signed session from /auth/validate Signed document minted in the cloud
Lifetime Session TTL: 1h to 7d Operator-chosen expiry or lifetime (perpetual licenses only)
Revocation Picked up at the next online validate / check-in Not reachable: the file stays valid until its own expiry
Cost 1 credit per login() 1 credit per mint; verifying is free
from authforge import AuthForgeClient

client = AuthForgeClient(
    app_id="YOUR_APP_ID",
    app_secret=None,  # login_from_file does not use the App Secret; do not ship it in air-gapped builds
    public_key="YOUR_PUBLIC_KEY",
    on_failure=lambda reason, exc: print(reason, exc),
)

# 1. Write an activation request the operator drops into the mint dialog:
client.write_activation_request("machine.authforge-request")

# 2. Later, authorize from the minted file (path or armored text). No network.
if client.login_from_file("license.authforge"):
    info = client.get_offline_license()
    print("Offline license OK until", info["expires_at"] or "forever")
    print(client.get_license_variables())

Collect the HWID from the same SDK build that will load the file: fingerprints are not portable across SDKs or languages. After login_from_file(), get_session_kind() returns "offline" ("online" after login(), None when logged out).

verify_license_file() (module function and client method) performs the same checks without touching client state. Failure codes, in check order: bad_armor, bad_signature, unsupported_version, malformed_payload, wrong_app, expired, hwid_mismatch. login_from_file() reports them through on_failure("offline_login_failed", exc) and returns False; it never calls os._exit.

File format (version 1): PEM-style armor with informational headers, a base64 JSON payload (v, appId, licenseKey, jti, kid, issuedAt, expiresAt, hwid policy, optional label/variable snapshots) and a detached Ed25519 signature over the UTF-8 bytes of the base64 payload string - the same contract as /auth/validate. See offline_license_vectors.json for conformance vectors.

Self-serve offline activation

A separate mode for apps that sell a one-time license and then run with no network: the end user types the license key once, activate_offline() makes one online call (POST /auth/offline/activate) and gets back a lifetime .authforge file bound to this machine's HWID. From then on the app starts with login_from_file() and never contacts AuthForge again.

How it differs from air-gapped offline files:

  • It needs the App Secret, because it is an online call. Air-gapped builds that only use login_from_file() still ship with app_secret=None.
  • The app owner opts the app in (app settings in the dashboard). Only perpetual, seat-limited licenses can self-serve; each license can produce files for at most maxHwidSlots distinct machines, ever. HWID resets do not free those machine slots.
  • Billing: a new machine costs the app owner 2 credits, once. The same machine activating again (reinstall, deleted file) gets the identical file back for free. A refused activation costs nothing.
  • A refund or chargeback revokes the license online but cannot reach files already issued. A lifetime file keeps working on its machine.
import os
import sys

from authforge import AuthForgeClient, AuthForgeError

LICENSE_PATH = os.path.join(os.path.expanduser("~"), ".myapp", "license.authforge")

client = AuthForgeClient(
    app_id="YOUR_APP_ID",
    app_secret="YOUR_APP_SECRET",  # required for activate_offline (online call)
    public_key="YOUR_PUBLIC_KEY",
    on_failure=lambda reason, exc: None,  # login_from_file reports why it failed here
)

# 1. No network, no credits: run from the file if it is there and valid.
if not (os.path.exists(LICENSE_PATH) and client.login_from_file(LICENSE_PATH)):
    # 2. No file yet, or it fails (e.g. hwid_mismatch after a hardware change).
    key = input("License key: ").strip()
    try:
        client.activate_offline(key, path=LICENSE_PATH)
    except AuthForgeError as exc:
        if exc.code == "offline_activation_limit_reached":
            print("This license is active on its maximum number of machines. Please contact the vendor.")
        elif exc.code in {"invalid_key", "revoked", "expired"}:
            print("That license key is not valid.")
        elif exc.code == "hwid_mismatch":
            print("No free seat on this license for this machine.")
        elif exc.transient:
            print(f"Could not activate right now ({exc.code}). Check your connection and try again.")
        else:
            print(f"Activation failed: {exc.code}")
        sys.exit(1)

print("Licensed:", client.get_license_variables())

activate_offline(license_key, path=None) returns True on success and raises AuthForgeError otherwise. It:

  1. Fails fast with the usual "app_secret is required" ValueError (no request) when the client has no App Secret.
  2. Sends appId, appSecret, licenseKey, the same HWID login() sends and a fresh nonce, with the same retries as login() (rate_limited after 2s then 5s, one retry on a network error).
  3. Verifies the returned file with your public key(s), app id and this machine's HWID before writing anything. A file that fails raises offline_file_rejected; the message includes the verifier's reason (bad_signature, wrong_app, hwid_mismatch, ...).
  4. If path is set, writes the file byte-for-byte and atomically (temp file in the same directory, then rename), creating parent directories.
  5. Leaves the client authenticated exactly as login_from_file() does: get_session_kind() is "offline", variables and get_offline_license() are set, no background checks start. get_offline_license()["replay"] is True when the server returned a file this machine already had.

On any failure nothing is written to path (an existing file there is left as it was), the call does not authenticate the client (an existing session is kept), and neither on_failure nor os._exit is called.

Code Kind Meaning
offline_activation_disabled fatal The app has not opted in to self-serve activation
offline_activation_requires_perpetual fatal The license has an expiry; only perpetual licenses can self-serve
offline_activation_requires_seats fatal Unlimited-seat (shared) licenses cannot self-serve
offline_activation_limit_reached fatal Every machine slot on the license is used; the buyer must contact the vendor
offline_file_rejected fatal SDK code: the returned file failed local verification; nothing was written
hwid_mismatch fatal No free seat on the license for this machine (server code, not the verifier's)
file_write_failed transient The verified file could not be written to path; activating again is free
invalid_key, revoked, expired, no_credits, rate_limited, unexpected_response, network_error, ... as everywhere else Existing codes keep their meaning and classification

Migrating from heartbeat_mode

Earlier releases required heartbeat_mode="LOCAL" or "SERVER". The argument is now optional and deprecated; it still works but emits a DeprecationWarning.

  • heartbeat_mode="LOCAL" maps to the default behavior (the grace period): just remove the argument.
  • heartbeat_mode="SERVER" maps to online_heartbeat=True.
  • If both arguments are set, either one enables online check-ins: heartbeat_mode="SERVER" is not overridden by online_heartbeat=False.
# Before
client = AuthForgeClient(app_id, app_secret, public_key, heartbeat_mode="SERVER")

# After
client = AuthForgeClient(app_id, app_secret, public_key, online_heartbeat=True)

For code that still reads it, client.heartbeat_mode remains available and reflects the effective policy ("SERVER" when online check-ins are enabled, "LOCAL" otherwise).

Billing

  • 1 login() or validate_license() call = 1 credit (one /auth/validate debit each).
  • 10 online check-ins on the same license = 1 credit (billed every 10th successful /auth/heartbeat). Grace period checks are local and free.
  • 1 new offline activation (activate_offline()) = 2 credits, charged to the app owner; re-activating the same machine is free. login_from_file() is always free.

A desktop app running 6h/day with online check-ins at a 15-minute interval burns ~3-4 credits/day. The server enforces /auth/heartbeat at 6 requests/minute per license key, so keep intervals at 10 seconds or higher and pick the interval based on how fast you need revocations to propagate (they always land on the next check-in).

Methods

Method Returns Description
login(license_key) bool Activates: validates the key online and stores the signed session (sessionToken, expiresIn, appVariables, licenseVariables)
validate_license(license_key) ValidateLicenseResult Same /auth/validate + signatures as login; does not store session or start background checks; returns a dict with valid / code and never calls on_failure or os._exit
self_ban(...) dict Requests /auth/selfban to blacklist HWID/IP and optionally revoke (session-authenticated only)
login_from_file(path_or_text) bool Authorizes from an offline .authforge file with no network; never starts background checks; failures go to on_failure("offline_login_failed", …)
activate_offline(license_key, path=None) bool Self-serve offline activation: one online call returns a lifetime HWID-bound .authforge file, verified locally, written atomically to path and applied like login_from_file. Needs the App Secret; raises AuthForgeError on refusal; never calls on_failure or os._exit
verify_license_file(path_or_text, *, now=None) VerifyLicenseFileResult Verifies a .authforge file with this client's app id / keys / HWID without changing state
get_offline_license() dict | None Metadata of the offline file in use (jti, expires_at, hwid_policy, …)
get_session_kind() "online" | "offline" | None Which kind of session the client holds (None when logged out)
get_hwid() str The HWID this client sends (or hwid_override); customers share it to receive a bound file
create_activation_request(**kwargs) str Unsigned .authforge-request for this machine. No network, no secret. Hostname omitted unless include_machine_name=True
write_activation_request(path, **kwargs) None Writes that file as UTF-8
logout() None Stops background checks and clears all session/auth state
is_authenticated() bool True when an active authenticated session exists
get_session_data() dict | None Full decoded payload map
get_app_variables() dict | None App-scoped variables map
get_license_variables() dict | None License-scoped variables map

Failure Handling

If authentication fails (activation rejected, check-in fails, signature mismatch, grace period expired, etc.), the SDK calls your on_failure callback if one is provided. Without a callback, a transient background check failure (network outage, rate_limited, system_error, ...) writes a one-line warning to stderr and check-ins continue; every other failure (a rejected login(), a definitive check-in answer, the grace period running out) calls os._exit(1) to terminate the process, so your app cannot keep running without a valid license. os._exit skips all cleanup, so set on_failure if your app has anything to save.

validate_license() does not trigger on_failure or os._exit: check result["valid"] and result["code"].

Recognized server errors (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, demo_quota_exceeded, system_error, and from activate_offline(): offline_activation_disabled, offline_activation_requires_perpetual, offline_activation_requires_seats, offline_activation_limit_reached, plus the SDK code offline_file_rejected. Codes added to the server later are passed through unchanged.

activate_offline() does not trigger on_failure or os._exit either: it raises AuthForgeError (see Self-serve offline activation).

Request retries are automatic inside the internal HTTP layer:

  • rate_limited, or HTTP 429 with no error code: retry after 2s, then 5s (max 3 attempts total)
  • no_credits, demo_quota_exceeded and app_burn_cap_reached also arrive as HTTP 429 but are never retried immediately; online check-ins try again at the next interval
  • network failure: retry once after 2s
  • every retry regenerates a fresh nonce

Background check failures

Background check failures reach on_failure("heartbeat_failed", exc), where exc is an AuthForgeError (a ValueError subclass):

  • exc.code: the server's error code from the response body, whatever the HTTP status (revoked, expired, hwid_mismatch, blocked, session_expired, rate_limited, no_credits, system_error, malformed_request, ...), or an SDK code: network_error, timeout, http_error_<status> (non-JSON error body), invalid_json_response, unexpected_response, signature_mismatch, nonce_mismatch.
  • exc.transient / exc.fatal: the classification. is_transient_error(code_or_exc) is the same check as a function; DEFINITIVE_ERROR_CODES is the full list of fatal codes.

A failed check-in only counts as an AuthForge verdict when the body is a JSON object with "status": "failed" and a non-empty error string. Any other failure body (for example a proxy's JSON, or {"status": "revoked"}) is reported as unexpected_response, whose message includes the raw status and error.

Kind Codes What the SDK does
Fatal revoked, expired, hwid_mismatch (the HWID is no longer bound to the license, for example after an HWID reset), blocked (HWID/IP blacklisted or not whitelisted), session_expired (also raised locally when the grace period or session TTL runs out), malformed_request, app_disabled, invalid_app, signature_mismatch (plus the activate_offline()-only codes offline_activation_* and offline_file_rejected) Clears the stored session (as logout() does) and stops background checks before calling on_failure, so the grace period cannot keep the app running on it. on_failure may call login() again.
Transient Everything else: network_error, timeout, rate_limited, system_error, no_credits, demo_quota_exceeded, app_burn_cap_reached, bad_request, invalid_key, every http_error_<status>, invalid_json_response, unexpected_response, nonce_mismatch, any unrecognized code Keeps the session and checks in again on the next heartbeat_interval. Once the signed session's TTL has passed, the next transient failure is reported as a fatal session_expired instead.

Transient failures only keep checking in if on_failure returns normally. Without a callback, a transient failure prints AuthForge: background check failed (<code>); retrying next interval to stderr and check-ins continue; a fatal one, including the session_expired a transient failure becomes once the session TTL has passed, still ends the process with os._exit(1). Heartbeat network failures are reported once, as heartbeat_failed with code network_error or timeout, not as a separate network_error reason.

on_failure runs on the background heartbeat thread with no SDK lock held, so calling logout(), is_authenticated() or login() from it is safe. A check-in that is still in flight when you call logout() or login() is discarded: it cannot restore the old session or report a failure for it.

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:

import sys
import threading
from authforge import AuthForgeClient, AuthForgeError

license_lost = threading.Event()

def handle_auth_failure(reason, exc):
    if reason == "heartbeat_failed" and isinstance(exc, AuthForgeError) and exc.transient:
        # Connectivity problem or AuthForge overloaded: keep running. The SDK
        # retries every heartbeat_interval and reports session_expired (fatal)
        # once the ttl_seconds grace period is used up.
        print(f"AuthForge check-in failed ({exc.code}), retrying", file=sys.stderr)
        return
    code = exc.code if isinstance(exc, AuthForgeError) else exc
    print(f"License check failed: {reason} ({code})", file=sys.stderr)
    # This can run on the heartbeat thread: signal the main thread instead of exiting here.
    license_lost.set()

client = AuthForgeClient(
    app_id="YOUR_APP_ID",
    app_secret="YOUR_APP_SECRET",
    public_key="YOUR_PUBLIC_KEY",
    online_heartbeat=True,
    ttl_seconds=3600,  # retry window for transient check-in failures
    on_failure=handle_auth_failure,
)

if not client.login(input("License key: ").strip()):
    sys.exit(1)

while not license_lost.is_set():
    do_one_unit_of_work()  # keep units short so the loop notices the signal quickly

save_user_work()
client.logout()
sys.exit(1)

If your main thread is blocked (for example in input() or a long time.sleep()) rather than looping, call _thread.interrupt_main() from the callback instead: it raises KeyboardInterrupt on the main thread, so your existing try / finally cleanup runs. sys.exit() inside the callback only ends the heartbeat thread. Calling os._exit(1) from the callback is a last resort for when the main thread cannot react at all: it skips finally blocks, atexit handlers and unflushed file writes, so save the user's work first.

Self-ban (tamper response)

Use self_ban() when anti-tamper checks trigger:

# Post-session (authenticated): defaults to revoke + HWID/IP blacklist.
client.self_ban()

# Pre-session: pass license_key, SDK automatically disables revoke_license.
client.self_ban(license_key="AF-XXXX-XXXX-XXXX")

# Custom flags:
client.self_ban(
    blacklist_hwid=True,
    blacklist_ip=True,
    revoke_license=False,
)

self_ban() automatically chooses mode:

  • Uses post-session mode when a session token is available (session_token arg or current SDK session).
  • Falls back to pre-session mode using license_key + nonce + app secret.
  • In pre-session mode, revoke is forced off client-side to avoid unsafe key revocations.
  • Not available after login_from_file(): offline sessions have no server session, so self_ban() with no explicit license_key / session_token raises ValueError("offline_session") without contacting the server.

How It Works

  1. Activate: login() uses hwid_override if provided; otherwise it collects a hardware fingerprint (MAC, CPU, disk serial). It then generates a random nonce and sends everything to the AuthForge API. The server validates the license key, binds the HWID, deducts a credit, and returns a signed payload with a TTL. The SDK verifies the Ed25519 signature and nonce to prevent replay attacks.

  2. Background checks: a daemon thread wakes at the configured interval. By default it enforces the grace period: it re-verifies the stored signature and checks expiry without network calls. With online_heartbeat=True, it instead sends /auth/heartbeat with a fresh nonce and verifies the response.

  3. Crypto: both /validate and /heartbeat responses are signed by AuthForge with your app's Ed25519 private key. The SDK verifies every signed payload using your configured public_key and rejects tampered responses.

Hardware ID

The SDK generates a deterministic hardware fingerprint by hashing:

  • MAC address
  • CPU identifier
  • Disk serial number

Each component falls back gracefully if it can't be read (e.g. permissions issues). The HWID is sent with every auth request so the server can enforce per-device license limits.

For non-device identities (for example Telegram users), pass hwid_override such as tg:<user_id>.

Test Vectors

The shared test_vectors.json file validates cross-language Ed25519 verification behavior. offline_license_vectors.json (generated from a fixed test seed in the Node SDK repo) is the cross-SDK conformance suite for .authforge offline license files: good files plus the bad_signature, wrong key, wrong_app, expired, hwid_mismatch, unsupported_version and bad_armor rejects. self_serve_activation_vectors.json is the cross-SDK suite for activate_offline(): mocked /auth/offline/activate responses with the expected written file, session and error code.

Requirements

  • Python 3.9+
  • Dependency: cryptography

License

MIT

Metadata

Release files for authforge-sdk 1.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for authforge-sdk 1.5.0
File Size Uploaded
authforge_sdk-1.5.0.tar.gz 47.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for authforge-sdk 1.5.0
File Interpreter ABI Platform
authforge_sdk-1.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 76.8 kB

Release files / authforge_sdk-1.5.0.tar.gz

Download URL authforge_sdk-1.5.0.tar.gz
Size 47.7 kB
Tags Source
SHA-256 checksum
How to use checksums
2c7008d6418b2d56000949a249e9deef40f8352ab18e5c04e8c70fb814a45e15
BLAKE2b-256 checksum
How to use checksums
6fecaecbecdcbb9dcedcb80f738e32c440c15ef51c615f2b4a95a08761fa6ef7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / authforge_sdk-1.5.0-py3-none-any.whl

Download URL authforge_sdk-1.5.0-py3-none-any.whl
Size 29.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4ef92d9427ff1eee27d9a2807b948c901d09cffeda3db01eae95a7ee7c58ad7c
BLAKE2b-256 checksum
How to use checksums
99b2ed8814ebf6e9226f6e8d232b2efb33e00d5f649428e212f7db15213f9d41
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.5.0 This release

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page