Client and manager helpers for Authlix
Project description
Authlix Python SDK
Client and manager helpers for integrating public validation flows and project operations with the Authlix API.
License client – validates license keys, collects environment metadata and lets end-users update client_editable fields.
Manager client – handles authentication plus CRUD operations for projects, metadata schemas, licenses and API keys.
Cryptographic signing – Ed25519 response signatures, SealedBox HWID encryption and anti-replay protection.
Environment helpers – gather HWID, local/public IPs and other contextual information.
The SDK targets Python 3.9+ and is published to PyPI as authlix.
Installation
pip install authlix
PyNaCl is included as a dependency and is required for the cryptographic signing features.
Quick start
Validate a license key
from authlix import LicenseClient
client = LicenseClient(
base_url="https://authlix.io",
project_id=42,
)
# Automatically collects HWID as machine fingerprint
result = client.validate_with_environment("CL-XXXX-XXXX")
print(result)
# {"valid": True, "expires_at": "2026-12-31T00:00:00", "metadata": {...}}
To control the payload manually, call validate_license and pass hwid, ip, and metadata yourself. The metadata must only contain fields that are marked client_editable in your project schema.
Validate with cryptographic security
When your project has crypto enabled, the SDK can encrypt the HWID, add anti-replay parameters and automatically verify the Ed25519 signature on every response:
from authlix import LicenseClient
client = LicenseClient(
base_url="https://authlix.io",
project_id=42,
)
# Fetch and cache the project's Ed25519 public key (once per session)
client.fetch_public_key()
# HWID is now encrypted with SealedBox; the response signature is auto-verified
result = client.validate_with_environment("CL-XXXX-XXXX")
Or embed the public key directly to avoid the extra round-trip:
client = LicenseClient(
base_url="https://authlix.io",
project_id=42,
public_key="<hex-encoded-ed25519-public-key>",
)
LicenseClient constructor options:
| Parameter | Default | Description |
|---|---|---|
public_key |
None |
Hex Ed25519 public key. Enables HWID encryption and signature verification. |
auto_verify |
True |
Verify Ed25519 signature on every response (requires public_key). |
anti_replay |
True |
Include timestamp + nonce in requests (requires public_key). |
Manage projects and licenses
from authlix import ManagerClient
manager = ManagerClient(base_url="https://authlix.io")
manager.authenticate("automation_bot", api_key="sk_live_XXXXXXXXXXXXXXXX")
# Create a project
project = manager.create_project(
name="My Awesome App",
description="Tooling pour la communauté",
)
# Create a 30-day license
license_data = manager.create_license(
project_id=project["id"],
days_valid=30,
metadata={"plan": "pro"},
)
# Revoke a license
manager.update_license(
license_id=license_data["id"],
is_active=False,
metadata={"plan": "revoked", "notes": "Chargeback"},
)
# Extend expiration by 14 days
manager.extend_license(project_id=project["id"], license_id=license_data["id"], days=14)
# Delegate day-to-day operations to a teammate
manager.add_project_manager(project_id=project["id"], username="support_team")
Look up a license by key
Prefer get_license_by_key over fetching the full list when you only need one license:
from authlix import ManagerClient, NotFoundError, ForbiddenError
manager = ManagerClient(base_url="https://authlix.io")
manager.authenticate("admin", api_key="sk_live_XXXXXXXXXXXXXXXX")
try:
lic = manager.get_license_by_key(project_id=42, license_key="CL-XXXX-XXXX")
print(f"ID: {lic['id']} active: {lic['is_active']}")
except NotFoundError:
print("Key not found in this project")
except ForbiddenError:
print("Insufficient permissions")
The key is automatically normalized to uppercase before lookup.
API key management
manager = ManagerClient(base_url="https://authlix.io")
manager.authenticate("admin", password="password")
# Create a key scoped to one project (raw secret returned once)
api_key = manager.create_api_key(
label="CI Runner",
project_ids=[project["id"]],
)
# Expand its scope later
manager.update_api_key(api_key_id=api_key["id"], project_ids=[project["id"], 7])
# Operator-wide audit view
manager.list_api_keys()
# Per-project view
manager.list_project_api_keys(project_id=project["id"])
# Retire when done
manager.delete_api_key(api_key_id=api_key["id"])
Client-editable metadata
Certain metadata fields can be safely mutated by end-users via the client_editable flag.
1. Manager defines the schema:
manager.update_metadata_schema(
project_id=42,
fields=[
{"name": "notes", "type": "string", "client_editable": True},
{"name": "plan", "type": "string", "client_editable": False},
],
)
2. Client updates the editable fields:
from authlix import LicenseClient
client = LicenseClient(base_url="https://authlix.io", project_id=42)
client.update_client_metadata(
key="CL-XXXX-XXXX",
metadata={"notes": "Nouvelle machine"},
)
update_client_metadata validates locally that project_id is an int and metadata is non-empty before calling POST /api/client_metadata.
Cryptographic signing (Ed25519)
Each project has an Ed25519 key pair. The server signs every validation response; the SDK encrypts the HWID with SealedBox and verifies signatures automatically.
Enable / disable crypto (owner only)
manager.toggle_crypto(project_id=42, enabled=True)
manager.toggle_crypto(project_id=42, enabled=False)
Retrieve the public key
# Via ManagerClient (authenticated)
data = manager.get_public_key(project_id=42)
public_key_hex = data["public_key"]
# Via LicenseClient (public endpoint, no auth)
client.fetch_public_key() # fetches & caches on client.public_key
print(client.public_key)
Rotate the signing key (owner only)
result = manager.rotate_signing_key(project_id=42)
print(result["signing_public_key"]) # distribute this new key to all SDK clients
WARNING — rotating invalidates all SDK instances still holding the old public key.
Manual signature verification
from authlix import verify_signature, SignatureVerificationError
try:
verify_signature(public_key_hex, response_payload)
except SignatureVerificationError as exc:
print(f"Signature invalid: {exc}")
Environment helpers
from authlix import collect_environment_metadata, get_machine_fingerprint, get_public_ip
# Stable machine fingerprint (SHA-256 of MAC + platform info)
hwid = get_machine_fingerprint()
# Public IP via ipify
ip = get_public_ip()
# Both at once (public IP optional)
meta = collect_environment_metadata(include_public_ip=True)
print(meta) # {"hwid": "...", "ip": "..."}
Error handling
from authlix import (
AuthlixError,
AuthenticationError,
ApiError,
BadRequestError,
ForbiddenError,
NotFoundError,
SignatureVerificationError,
)
try:
result = client.validate_with_environment("CL-XXXX-XXXX")
except SignatureVerificationError as exc:
# Ed25519 signature mismatch — possible tampering
print(f"Signature invalid: {exc}")
except BadRequestError as exc:
print(f"Bad request (400): {exc}")
except ForbiddenError as exc:
print(f"HWID mismatch or inactive license (403): {exc}")
except NotFoundError as exc:
print(f"License not found (404): {exc}")
except ApiError as exc:
print(f"API error {exc.status_code}: {exc} payload={exc.payload}")
except AuthlixError as exc:
print(f"SDK error: {exc}")
| Exception | HTTP | When |
|---|---|---|
BadRequestError |
400 | Missing / invalid parameters |
ForbiddenError |
403 | HWID mismatch, inactive license, insufficient scope |
NotFoundError |
404 | Unknown license key or project |
SignatureVerificationError |
— | Ed25519 signature verification failed |
ApiError |
≥400 | Any other server error |
AuthenticationError |
— | Login failed or JWT missing |
AuthlixError |
— | Base class for all SDK exceptions |
ManagerClient reference
| Method | Description |
|---|---|
authenticate(username, *, password, api_key) |
Login and store JWT |
list_projects() |
List all accessible projects |
create_project(name, description) |
Create a new project |
add_project_manager(project_id, username) |
Delegate back-office access |
update_metadata_schema(project_id, fields) |
Define project metadata schema |
list_licenses(project_id) |
List all licenses for a project |
get_license_by_key(project_id, license_key) |
Efficient single-key lookup |
create_license(project_id, days_valid, metadata) |
Generate a new license |
update_license(license_id, *, is_active, expires_at, reset_hwid, metadata) |
Update a license |
extend_license(project_id, license_id, days) |
Push expiration forward |
delete_license(license_id) |
Hard-delete a license |
list_api_keys() |
Operator-wide API key list |
create_api_key(label, *, project_ids, allow_all_projects) |
Mint a scoped API key |
update_api_key(api_key_id, *, label, project_ids, allow_all_projects) |
Update key scope |
delete_api_key(api_key_id) |
Revoke an API key |
list_project_api_keys(project_id) |
Per-project API key list |
get_public_key(project_id) |
Fetch Ed25519 public key (no auth) |
toggle_crypto(project_id, enabled) |
Enable/disable signing (owner) |
rotate_signing_key(project_id) |
Regenerate key pair (owner) |
Examples
See the examples/ directory for runnable scripts:
examples/client/— validation, crypto, metadata update, error handlingexamples/manager/— project setup, license management, API keys, crypto
Local development
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
python -m pytest tests/ -v
python -m build
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file authlix-0.4.0.tar.gz.
File metadata
- Download URL: authlix-0.4.0.tar.gz
- Upload date:
- Size: 17.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12889361ba6152eea2a3e0b85ae417a5678052865484d20f19b0432163ab6029
|
|
| MD5 |
580cad6980f518d3c900e248c48ea6f7
|
|
| BLAKE2b-256 |
d974657fa3878b69e33ded784cec1a35e3ea471e6c795f1c3c0c609733edd1ea
|
File details
Details for the file authlix-0.4.0-py3-none-any.whl.
File metadata
- Download URL: authlix-0.4.0-py3-none-any.whl
- Upload date:
- Size: 13.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04f05add25ef7152edaebd58a9aab15968d22e500fcba0b530f45de1b8630791
|
|
| MD5 |
a4f5642729c4fdbf2382ae74393f7394
|
|
| BLAKE2b-256 |
4bd32b1e3061ef87e4181907ed366b18e0c8e01f4ea327422ddefa0398f03603
|