keywarden
The official Python client for Key-Warden. Validate a software licence online — seat-aware, revocation-aware — or verify a signed token offline against your embedded public key, with no network round-trip.
One dependency: cryptography (for
Ed25519). Networking is stdlib urllib. Python 3.8+.
pip install keywarden
Validate online
The authoritative check. Ask the platform whether a licence is good right now.
import os, socket
import keywarden as kw
res = kw.validate(
customer_licence_key,
apim_key=os.environ["KW_APIM_KEY"], # your APIM subscription key
client_key=os.environ["KW_CLIENT_KEY"], # your validation key
machine_id=kw.machine_id_from(socket.gethostname(), user_id), # stable, hashed your side
)
if not res["valid"]:
raise SystemExit(f"licence not valid: {res.get('reason')}")
# res["token"] is a freshly signed proof — cache it for the offline path below.
A valid == False (e.g. revoked, expired, seat_limit_exceeded) is data,
not an error. A wrong client_key raises a KeyWardenError with
code == "unauthorized_client" — that's your auth failing, and your customer
should never see it as a licence problem.
Verify offline
No connection? Verify a token you already hold against your public key — the 32-byte raw key from your vendor console. Pure, no network.
check = kw.verify_token(cached_token, os.environ["KW_PUBLIC_KEY"])
if not check["valid"]:
lock_features(check["reason"]) # "bad_signature" | "expired" | ...
The token is header.body.signature (compact JWT style) and the Ed25519
signature covers the exact bytes header.body. This client verifies over those
bytes — it never decodes-then-reverifies, which is the one mistake that silently
breaks offline checks. Expiry is honoured within the offline grace window you set
at mint time.
Online, with an offline fallback
The pattern most desktop apps want: online is authoritative; if the network is down, keep working within grace.
res = kw.validate_or_verify(
customer_licence_key,
apim_key=apim_key, client_key=client_key, machine_id=machine_id,
cached_token=last_good_token, # from a previous validate()
public_key=os.environ["KW_PUBLIC_KEY"],
)
# res["source"] == "online" | "offline"
A rejected client_key (401) is never masked by the offline path — only a genuine
reachability failure falls back.
API
| Function | Purpose |
|---|---|
validate(key, *, apim_key, client_key, ...) |
Online check. Returns {"valid", "reason"?, "activeSeats"?, "token"?}. |
verify_token(token, raw_pub_b64, *, now=None) |
Offline check. Returns {"valid", "reason"?, "claims"?}. |
validate_or_verify(key, *, cached_token, public_key, ...) |
Online, falling back to a cached token when unreachable. |
machine_id_from(*parts) |
A stable SHA-256 machine id; raw parts never leave the machine. |
Any real failure (bad credentials, unreachable gateway, server error) raises
KeyWardenError, which carries .code and .status.
Security notes
- Your private signing key never leaves Key-Warden's Key Vault. You embed only the 32-byte public half.
machine_idis hashed by the platform, but send an opaque, stable id — not a raw MAC address or a hostname you wouldn't want logged.machine_id_from()hashes on your side too.- Two independent credentials gate every online call: the APIM subscription key gets you to the gateway, the validation key authenticates you as the vendor. A leaked validation key can be rotated without reissuing a single customer licence.
Licence
MIT.
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 keywarden-1.0.0.tar.gz.
File metadata
- Download URL: keywarden-1.0.0.tar.gz
- Upload date:
- Size: 7.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
645c1e7bc748b56eabbeae043f54cb6242ec1b8cc1b03c9ae6a50d8a996e6060
|
|
| MD5 |
78f83f16903be713eebdfac8583ea264
|
|
| BLAKE2b-256 |
45125bdcd86a72845c41834ab42b98dd2566e4d60e1bfd3593339cd58079c902
|
File details
Details for the file keywarden-1.0.0-py3-none-any.whl.
File metadata
- Download URL: keywarden-1.0.0-py3-none-any.whl
- Upload date:
- Size: 7.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5bb45bdd2ec92a12082b337f00b32aa411bb9b50023e72f8826f351e3aedddb
|
|
| MD5 |
cb485573895001ab7e180e8c60e0b7b9
|
|
| BLAKE2b-256 |
c57e1d879d5773dc10a49c3b133a4f969b93f1cede948bb62fe905e5f4f7482c
|