Skip to main content

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_id is 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

keywarden-1.0.0.tar.gz (7.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

keywarden-1.0.0-py3-none-any.whl (7.5 kB view details)

Uploaded Python 3

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

Hashes for keywarden-1.0.0.tar.gz
Algorithm Hash digest
SHA256 645c1e7bc748b56eabbeae043f54cb6242ec1b8cc1b03c9ae6a50d8a996e6060
MD5 78f83f16903be713eebdfac8583ea264
BLAKE2b-256 45125bdcd86a72845c41834ab42b98dd2566e4d60e1bfd3593339cd58079c902

See more details on using hashes here.

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

Hashes for keywarden-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f5bb45bdd2ec92a12082b337f00b32aa411bb9b50023e72f8826f351e3aedddb
MD5 cb485573895001ab7e180e8c60e0b7b9
BLAKE2b-256 c57e1d879d5773dc10a49c3b133a4f969b93f1cede948bb62fe905e5f4f7482c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page