Skip to content

docs: separate client-key and admin-key usage; describe installation ID accurately - #10

Merged
catsika merged 1 commit into
mainfrom
docs/separate-client-and-admin-keys
Nov 13, 2026
Merged

catsika merged 1 commit into
mainfrom
docs/separate-client-and-admin-keys

Conversation

@catsika

@catsika catsika commented Nov 12, 2026

Copy link
Copy Markdown
Member

README and doc-comment changes only. No code behaviour changes.

Client key vs admin key

The usage example called CreateKey, which needs an admin key, right next to code that reads this machine's installation ID. Copied into a desktop app, that ships an admin key. The example is now two labelled parts:

  • In your app (client key): GetOrCreateInstallationID, ActivateKey (also used to re-check at start-up, since re-activating the same host reuses its slot), DeactivateKey with HostID (required for client keys). Uses a product-bound client key.
  • On your server (admin key): CreateCustomer, CreateKey (with AllowedHosts as an optional value reported by the app), BlockKey, UnblockKey. Loads the key from the server environment.

It also says why: anything compiled into an app can be extracted. A note lists which calls need admin and which need at least read-only (GetKey, the customer reads), so those stay on the server too.

The Offline Licenses section showed SignKey "while the machine is online", which reads as in-app. SignKey needs an admin key, so it is now shown on the server, with the app sending its host ID and receiving the .lic file. The idempotency example (CreateKey) is marked as server code.

Machine Identity

The README said GetOrCreateInstallationID "Generates a stable UUID anchored to hardware". What Identity.go does: on first call it joins a random UUIDv4, the GetMachineID() fingerprint (empty if unreadable) and a millisecond timestamp, writes that to ~/.keymint/installation-id (OS temp dir if there is no home dir), and returns the SHA-256 of the file contents. So the ID is random and file-backed, not anchored to hardware: hardware changes don't affect it, but deleting the file, reinstalling the OS or running as another OS user gives a new one. If the write fails, no error is returned and each call produces a new ID. The README and the function's doc comment now say this (the doc comment claimed "guaranteed-unique, guaranteed-stable" and "UUIDv4 seeded with hardware info").

GetMachineID() was described as based on "BIOS UUID, OS machine ID, and MAC address". It hashes the first usable one of those (on macOS the "OS machine ID" layer is the hardware serial number). Reworded.

Other fixes

  1. GetCustomerWithKeys was described as "Gets a customer along with their license keys". It returns only the customer's keys (a flat list). Reworded.
  2. The error-handling example printed *apiErr.Status. Status is nil when no HTTP response arrived (for example a network failure, Code == -1), so the example could panic. It now prints apiErr.Code.
  3. "Uniquely identify machines" in the Machine Identity intro is now "identify an installation".

Checks

  • go vet ./... and go build ./... pass.
  • The two new package main examples were compiled against this branch.

…ID accurately

Split the README usage example into an in-app part (product-bound client
key: installation ID, activate, deactivate) and a server part (admin key:
create keys and customers, block, unblock), and say why an admin key must
never ship in an app. SignKey is shown on the server, since it needs an
admin key.

Describe GetOrCreateInstallationID as what it is: a random ID combined
with the machine fingerprint and a timestamp, hashed and saved to disk,
not anchored to hardware. Same for its doc comment.

Also: GetCustomerWithKeys returns the customer's keys only, and the error
handling example no longer dereferences a possibly nil Status.
@catsika
catsika merged commit b410184 into main Nov 13, 2026
2 checks passed
@catsika
catsika deleted the docs/separate-client-and-admin-keys branch November 13, 2026 01:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant