Skip to main content

sdkey

Official Python client for SDKey license authentication.

Implements the sealed session protocol: Ed25519-verified handshake, HKDF session keys, and AES-256-GCM envelopes for validate plus client auth (register / login / upgrade). See PROTOCOL.md.

Install

pip install sdkey

Requires Python 3.10+.

Quick start

Embed these values from the SDKey dashboard when you ship your app. app_version must exactly match the application version configured on the server (clientVersion on session init); mismatch returns APP_OUTDATED.

from sdkey import SdkeyClient, SdkeyError

client = SdkeyClient(
    api_base_url="https://api.sdkey.dev",
    app_id="YOUR_APP_ID",
    app_version="1.0.0",
    app_public_key_b64="YOUR_APP_PUBLIC_KEY_BASE64",
)

try:
    # hwid is optional (omit for web clients — server skips HWID checks)
    result = client.validate("SDKY-XXXX-XXXX-XXXX-XXXX", "machine-hwid")
    if result.success:
        print("licensed", result.status, result.expires_at, result.subscription_tier)
        print("message", result.message)
    else:
        print("denied", result.code, result.message)
except SdkeyError as err:
    # Init / transport failures use `error` text from the server when present
    print(err.code, err.message)
    raise

validate, register, login, and upgrade call init() automatically when no session exists and reuse an active session when present. Sessions last ~15 minutes server-side; on SESSION_EXPIRED the client clears local state so the next call re-handshakes.

Hardware ID (desktop)

Use get_hardware_id() on desktop apps to bind a license to the machine. It is opt-in — pass the result explicitly; the client never auto-injects HWID.

from sdkey import SdkeyClient, get_hardware_id

client = SdkeyClient(...)
result = client.validate("SDKY-XXXX-XXXX-XXXX-XXXX", get_hardware_id())

get_hardware_id() reads a stable OS machine identifier (Windows MachineGuid, Linux /etc/machine-id, macOS IOPlatformUUID), then returns the lowercase SHA-256 hex digest. On unsupported platforms or missing IDs it raises SdkeyError with code HWID_UNAVAILABLE — it does not invent a random ID. Omit hwid for web clients.

Client auth (sealed)

Register, login, and upgrade use the same sealed-session wire model as validate. Application binding and version gating come from the crypto session — do not send appId / clientVersion in the auth body.

reg = client.register(
    username="player1",
    password="••••••••",
    license_key="SDKY-XXXX-XXXX-XXXX-XXXX",
    hwid="machine-hwid",  # optional
)
if not reg.success:
    # Sealed failures expose plaintext `message` on ClientAuthResult.error
    print(reg.code, reg.error)
else:
    print(reg.session_token, reg.user, reg.license)

login = client.login(username="player1", password="••••••••")
upgrade = client.upgrade(username="player1", license_key="SDKY-HIGHER-TIER-KEY")

upgrade takes username + license key only (no password). The new key’s subscriptionTier must be strictly greater than the user’s current tier.

Breaking change (0.4.0): plaintext JSON client-auth bodies are rejected when the API has CRYPTO_ENFORCE=true (400 CRYPTO_REQUIRED). Use this SDK (or another sealed client) against production.

Where message vs error appears

Per-app responseMessages may customize many strings. The SDK surfaces whatever the server returns.

Surface Success text field Failure text field
Session init (none) error (raised as SdkeyError.message)
Sealed validate message message
Sealed register / login / upgrade message message (exposed as ClientAuthResult.error)

Example JSON shapes

Init failure (plaintext):

{ "success": false, "error": "Client version outdated", "code": "APP_OUTDATED" }

Sealed validate success (message):

{
  "success": true,
  "code": "OK",
  "message": "validated",
  "status": "active",
  "expiresAt": "2026-01-01T00:00:00.000Z",
  "subscriptionTier": 0,
  "sessionId": "...",
  "timestamp": 1720000001,
  "v": 1
}

Sealed validate failure (still message, not error):

{
  "success": false,
  "code": "HWID_MISMATCH",
  "message": "Hardware ID mismatch",
  "status": null,
  "expiresAt": null,
  "sessionId": "...",
  "timestamp": 1720000001,
  "v": 1
}

Sealed client auth failure (message inside the opened plaintext):

{
  "success": false,
  "code": "TIER_NOT_HIGHER",
  "message": "License tier must be higher than the current tier",
  "sessionId": "...",
  "timestamp": 1720000001,
  "v": 1
}

API

SdkeyClient(options)

Option Type Description
api_base_url str API origin (no trailing slash)
app_id str Application UUID
app_version str Exact app version → sent as clientVersion on session init
app_public_key_b64 str Raw Ed25519 public key (32 bytes), base64
http_post callable Optional HTTP POST override (tests / custom transport)

Methods

  • init() — challenge handshake; verifies the signed hello; derives the AES session key; sends clientVersion
  • validate(license_key, hwid=None) — sealed validate; omits hwid JSON key when not provided; always decrypts then verifies the Ed25519 signature before trusting success
  • register(...) / login(...) / upgrade(...) — sealed POST /api/v1/client/* (same outer envelope + verify order as validate)
  • get_session() / clear_session() — inspect or drop the local session
  • get_hardware_id() — package-level helper; SHA-256 hex of a stable OS machine ID (desktop opt-in)

Errors

Protocol / transport failures raise SdkeyError with a code and message (server error text when the API provides one):

INIT_FAILED · APP_OUTDATED · HELLO_SIGNATURE_INVALID · VALIDATE_RESPONSE_INVALID · RESPONSE_INVALID · RESPONSE_SIGNATURE_INVALID · SESSION_MISMATCH · CLOCK_SKEW · NETWORK · HWID_UNAVAILABLE

License denials (banned, HWID mismatch, etc.) return a normal ValidateResult with success=False — they are not raised. Auth denials return ClientAuthResult(success=False, code=..., error=...) where error is the sealed plaintext message.

This package does not include developer tooling / Bearer (sdk_live_…) management APIs.

Security notes

  • Never ship app private keys in a client.
  • Do not skip signature verification — that is the anti-spoof binding.
  • This package is open source; the SDKey server remains a separate product.

Development

python -m pip install -e ".[dev]"
pytest

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sdkey-0.4.0.tar.gz (20.2 kB view details)

Uploaded Source

Built Distribution

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

sdkey-0.4.0-py3-none-any.whl (15.2 kB view details)

Uploaded Python 3

File details

Details for the file sdkey-0.4.0.tar.gz.

File metadata

  • Download URL: sdkey-0.4.0.tar.gz
  • Upload date:
  • Size: 20.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for sdkey-0.4.0.tar.gz
Algorithm Hash digest
SHA256 f350890580c82650af55e4d047fc22707f8caa53ad605fa87f1c62af230f9e12
MD5 ef06f927137cf70a97054796f660a8ff
BLAKE2b-256 de65022649aa37528d68f5016d316b7d780aa18be0055efbf1ebf969dc711c09

See more details on using hashes here.

Provenance

The following attestation bundles were made for sdkey-0.4.0.tar.gz:

Publisher: publish.yml on SDKeyDev/sdkey-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sdkey-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: sdkey-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 15.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for sdkey-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b3fb960f5718bf4741f9103986643f2414d589dcb3ae19d7a054bf5b7d0d0a99
MD5 dfa2f295f602f0d27a2d34b05e0b9a1f
BLAKE2b-256 59cb26e9f2c03be8bc3f0bf8839f1f0e4c82f17a03c4febb8636cfac0ef22be4

See more details on using hashes here.

Provenance

The following attestation bundles were made for sdkey-0.4.0-py3-none-any.whl:

Publisher: publish.yml on SDKeyDev/sdkey-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

2 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