Python SDK for GrebKey license key validation, see grebkey.efraim.us
Project description
GrebKey
Python SDK for validating GrebKey license keys inside your application. It works completely remotely and makes it easy to implement features like machine activation, expiration, and offline grace periods. The SDK handles caching and retries so your users stay licensed even if the API is temporarily unreachable. This sdk is designed to be simple and secure, with no sensitive information stored on the client side. It identifies machines using stable OS-level identifiers without relying on hardware serial numbers or MAC addresses, making it robust across different environments and user permissions.
Install
pip install grebkey
Quickstart
from grebkey import GrebKeyClient, GrebKeyError
client = GrebKeyClient(
api_url="https://grebkeyapi.efraim.us",
product_id="prod_abc123",
)
try:
result = client.validate("GREB-XXXX-XXXX-XXXX-XXXX")
except GrebKeyError:
print("Could not verify license.")
exit(1)
if result.valid and result.machine_activated:
print("Licensed!")
else:
print(f"Not licensed: {result.reason}")
Runnable first-validation example
For a maintained, end-to-end example that uses environment configuration,
machine fingerprinting, cache/offline grace, explicit exit codes, and
non-secret failure output, see
examples/first_validation.py and the
recruited-developer instructions.
From this package directory, the configured example runs with:
python -m examples.first_validation
Verify its SDK/API contract locally without contacting the live service:
python -m pytest tests/test_first_validation_example.py -q
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
api_url |
str | required | Base URL of your GrebKey API |
product_id |
str | None | Restrict validation to a specific product |
cache_ttl |
int | 3600 | Seconds before re-validating over the network |
grace_period |
int | 86400 | Seconds the app keeps working if the API is unreachable |
cache_dir |
str | ~/.grebkey/cache |
Directory for the local cache file |
timeout |
int | 10 | HTTP request timeout in seconds |
Caching and offline behavior
On every validate() call:
- If a cached result exists and is younger than
cache_ttl, it's returned immediately (no network call). - If the cache is stale, the SDK hits the API and updates the cache.
- If the API is unreachable and a cached result exists within the
grace_period, that cached result is returned withresult.from_cache = True. - If the API is unreachable and no valid cache exists (or grace period expired),
GrebKeyNetworkErroris raised.
Cache files are stored at ~/.grebkey/cache/ with permissions 0600 (owner read/write only). The license key itself is never stored — only a hash of it is used as the filename.
Machine fingerprinting
The SDK automatically identifies the current machine by hashing together stable OS-level identifiers:
- Linux:
/etc/machine-id - macOS:
IOPlatformUUIDfromioreg - Windows:
MachineGuidfrom the registry
Hostname and username are included as fallback signals. The result is a SHA-256 hex string that stays stable across reboots and app updates without requiring admin privileges.
Access it directly with client.get_fingerprint().
Error handling
from grebkey import GrebKeyError, GrebKeyNetworkError, GrebKeyAPIError
try:
result = client.validate(key)
except GrebKeyNetworkError:
# API unreachable and no valid cache / grace period expired
pass
except GrebKeyAPIError as e:
# API returned 4xx or 5xx
print(e.status_code, e.message)
except GrebKeyError:
# Catch-all for any other GrebKey error
pass
Full API reference
GrebKeyClient
client.validate(key) -> ValidationResult
Check whether the license key is valid and this machine is authorized.
result.valid # bool
result.reason # str | None — "invalid_key", "expired", "suspended", "revoked", "product_mismatch"
result.key_id # str
result.product_id # str
result.metadata # dict
result.max_activations # int
result.current_activations # int
result.remaining_activations # int
result.machine_activated # bool — is THIS machine activated?
result.expires_at # str | None — ISO timestamp
result.from_cache # bool — served from local cache?
client.activate(key, api_key=None, label=None) -> ActivationResult
Register this machine against the license key.
Warning: The
api_keyparameter requires agk_live_secret key. Never embed this in client software shipped to end users. Use this method server-side only, or proxy through your own backend.
activation.id # activation ID
activation.fingerprint # machine fingerprint used
client.deactivate(key, api_key=None)
Remove this machine's activation. Same auth considerations as activate().
client.get_fingerprint() -> str
Return the stable machine fingerprint (SHA-256 hex string) for the current machine.
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 grebkey-0.1.7.tar.gz.
File metadata
- Download URL: grebkey-0.1.7.tar.gz
- Upload date:
- Size: 17.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cbf220efe84174c55a7f1031dba83e91ec6cd0440eb1b53a5bbbaef966e20c21
|
|
| MD5 |
c405567f22154c57453754847e19f25f
|
|
| BLAKE2b-256 |
b359ce472e02249b30df83ffd2738b687a21345fc3bcd2eb41929337887376da
|
File details
Details for the file grebkey-0.1.7-py3-none-any.whl.
File metadata
- Download URL: grebkey-0.1.7-py3-none-any.whl
- Upload date:
- Size: 9.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a3a14804b800530ce449106a372abb0b3f683c51b4a487725a534107772ff0c
|
|
| MD5 |
30f4fa96910309f7f0546a8d706c05bd
|
|
| BLAKE2b-256 |
0f82477b184900e5b88651158e1b89419621e4d49aad124ee3cbe9e552263d85
|