Skip to content

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

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 XML 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 already said SignKey needs an admin key, but also said to call it "while the machine is online", which reads as in-app. 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 Services/Identity.cs does: on first call it joins a random GUID, the GetMachineId() fingerprint (empty if unreadable) and a millisecond timestamp, writes that to ~/.keymint/installation-id under the user profile folder, 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, the exception is swallowed and each call produces a new ID. The README and the XML doc comment now say this. The doc comment claimed "guaranteed-unique, guaranteed-stable" and a "UUIDv4 seeded with hardware info", and its <exception> tag said write failures throw IOException; only reading an existing file can throw.

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) and returns null if none is readable. Reworded.

Other fixes

  1. GetCustomerWithKeys was described as "Gets a customer along with their license keys". It returns only the customer's keys. Reworded.
  2. "Uniquely identify machines" in the Machine Identity intro is now "identify an installation".

Checks

dotnet is not installed on the machine this was prepared on, so dotnet build was not run. The only source change is inside /// XML doc comments; the new <see cref="GetMachineId"/> refers to a method in the same class.

…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 GUID combined
with the machine fingerprint and a timestamp, hashed and saved to disk,
not anchored to hardware. Same for its XML doc comment, which also no
longer claims write failures throw.

Also: GetCustomerWithKeys returns the customer's keys only.
@catsika
catsika merged commit cd1f714 into main Nov 13, 2026
2 checks passed
@catsika
catsika deleted the docs/separate-client-and-admin-keys branch November 13, 2026 01:10
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