minmaxkey

SDKs

SDKs (Python & Go)

Two flavors of the same thing: fingerprint the machine, activate, verify offline tokens, and auto-revalidate. Pick the one that fits your stack — or shell out to the Go mmk binary from anything.

Python — sdk/python/mmk.py

One file, zero HTTP dependencies (stdlib urllib), cryptography for offline verification only.

Install

pip install cryptography        # the only dependency

Quickstart

import sys
import mmk

client = mmk.MMK(
    base_url="http://localhost:8080",
    product_id=1,
    api_key="<product api key>",               # from POST /v1/products
    public_key_pem=open("product.pub.pem").read(),  # from the same response
)

On purchase (or first run)

result = client.activate("9TMC-5TS9-0MKQ-VS8A-87Q0", name="My MacBook")
if result.get("status") != "active":
    sys.exit(f"activation failed: {result}")
# the offline token is cached automatically

On every launch

claims = client.ensure_valid()
if claims is None:
    sys.exit("license invalid — please check your key")

ensure_valid() is the whole story:

  1. cached token exists and its signature / expiry / fingerprint check out → instant approval, no network,
  2. otherwise it calls validate once; a fresh signed token is cached,
  3. revoked or expired → None → you deny.

Deactivation (optional — frees a seat)

client.deactivate()

Go — sdk/go (library + mmk binary)

Pure Go standard library — zero external modules, cross-compiles everywhere, and the CLI is a single static binary with no runtime. If your stack isn't Python (Tauri, Go apps, C++, Unity), this is your path.

Build

cd sdk/go
go build ./cmd/mmk              # mmk.exe on Windows, mmk on Linux/macOS
GOOS=linux GOARCH=amd64 go build ./cmd/mmk   # cross-compile for a server/CI

CLI quickstart

./mmk fingerprint
# 6805c498fd6654ede932a2d67949da69a96d44115ec8e7ba7cec94d5c8f4220b

./mmk activate --url http://localhost:8080 --product 1 \
  --api-key <product api key> --key 9TMC-5TS9-0MKQ-VS8A-87Q0 \
  --name "My MacBook" --platform macos
# {"status": "active", "license": {...}, "offline_token": "eyJ..."}

./mmk check --url http://localhost:8080 --product 1 \
  --api-key <product api key> --pubkey product.pub.pem
# VALID  license 9TMC-5TS9-0MKQ-VS8A-87Q0 (policy: lifetime)

./mmk verify --pubkey product.pub.pem --token "eyJ..." --fingerprint 6805c498...

check is the offline-first path: a cached token that verifies (signature, expiry, fingerprint) is accepted with zero network; otherwise it revalidates and refreshes the cache. Config can also come from env vars: MMK_URL, MMK_PRODUCT_ID, MMK_API_KEY, MMK_LICENSE_KEY.

As a library

import "minmaxkey.dev/mmk"

c := mmk.NewClient("http://localhost:8080", 1, apiKey, publicKeyPEM, licenseKey)
claims, err := c.EnsureValid()          // offline-first, caches token
if err != nil {
    log.Fatal("not licensed")
}
fmt.Println("licensed for", claims.Sub)

mmk.VerifyToken(token, publicKeyPEM, fingerprint) does the offline check in any context — embed it in your Go app, or call the binary from CI.

Machine fingerprinting

Both SDKs hash the most stable hardware identifier they can find:

  • Windows — registry MachineGuid
  • Linux — /etc/machine-id (or DMI product UUID)
  • macOS — IOPlatformUUID (ioreg)
  • fallback — hostname + machine type

It's deterministic on a given install, survives reboots, and changes on OS reinstall — that's by design, and it's why the dashboard has a reset seats button. It's a friendly binding, not a security boundary.

Offline verification

from mmk import verify_token
claims = verify_token(token, client.public_key_pem, expected_fingerprint=client.fingerprint)
# raises ValueError on bad signature / expiry / wrong machine
claims, err := mmk.VerifyToken(token, publicKeyPEM, fingerprint)

The API key question

Your app ships with the product api_key — that's fine. It only gates operations the license key + fingerprint already authorize, and it's how the server distinguishes your product. Treat the license key itself as the credential.

Roadmap notes

  • TypeScript / C# ports will land as the server API stabilizes — the wire format is language-agnostic.