← Cody McCodeface

How licenses work

A license for the Mac app is a small signed file, made for one Mac. Your own devices check it, with no call to us, so it works offline and keeps working for as long as that Mac has it.

You buy a license for the Mac app once, for one Mac; the headset and web clients are free. The website takes the payment and nothing else: the license is made by the Mac app. For the first 14 days the license is refundable, and during that time we can tell which purchase it belongs to — that is what makes a refund possible. After that the app exchanges it for a private license, which our server signs without being able to read it (a blind signature), so nothing we store connects a private license to a payment. The owner of a license is a key in the Mac’s Keychain, used after Touch ID: revoking a private license, or moving it to another Mac, takes that key. Our staff can cancel a license only while it is still refundable: an owner can cancel one directly, anyone else’s cancel needs an owner’s approval — owners are appointed only through a hardware key that is on no server. Once a license is private, only its owner can revoke it: no staff power over private licenses exists or is planned.

The limits of this system cost us, not you. A patched app, or a license copied from a Mac without a security chip, is a sale we did not make. If our server were ever taken over, the intruder would find no names, no addresses, no private licenses and nothing that ties a license to the person who bought it; they could not appoint staff or get the apps to trust a new key. What they could do is sign licenses for free until we distrust the key they found — lost sales, not lost privacy. Each limit is listed on this page, with what bounds it.

The Hitchhacker’s Guide to the GUI, Entry 1: Licenses · 3 min 17 s · captions on. The pictures were made with AI tools and are illustrations; the page below is the exact description.

  1. 0:00 The Hitchhacker'S Guide To The Gui
  2. 0:09 Most licenses know who you are.
  3. 0:21 The website takes the payment. That is all it does.
  4. 0:35 First license: refundable.
  5. 0:51 Second license: signed blind.
  6. 1:22 The owner is whoever holds the key.
  7. 1:32 Checked offline: "Sign this."
  8. 1:55 One license, one computer. Moving is free.
  9. 2:06 Who watches us?
  10. 2:29 The limits cost us, not you.
  11. 3:01 Built, or planned? The page below says which.
Transcript

This is the Hitchhacker's Guide to the GUI: a reference for people who would like their software to mind its own business.

Entry one. Licenses.

Most software licenses work like a hotel wristband. It proves you paid. It also tells the front desk where you are,

what you ordered, and when you went to bed. We thought this a bit much for a small app.

So here is what happens when you buy Cody. The website takes your payment and hands your computer a ticket, good for exactly one license.

That is the website's entire job. It does not write the license, and it never sees the one you end up with.

Your computer writes its own license and sends it in to be signed. This first one is refundable.

We keep a note matching it to its payment, and nothing else: no name, no email, nothing about you.

That note is how we are able to give you your money back.

Meanwhile, your computer prepares a second license and seals it in an envelope lined with carbon paper. When the refund window closes,

it sends us the envelope. We sign the outside. The signature presses through onto the license inside.

We never open it. The first license is canceled, the second takes its place,

and from then on we cannot tell which license is yours. This is called a blind signature.

It is standard, published mathematics, and not, as it sounds, a party trick.

Who owns the license? Whoever holds its key. The key lives in your computer's keychain, behind your fingerprint.

Not in an account, because there isn't one.

Each license also names one particular computer, by a key locked inside that computer's security chip.

When your headset wants to know whether this computer is licensed, it does not ask us.

It hands the computer a random number and says: sign this. Only that one computer can.

No internet required, which is convenient on airplanes and in sheds.

Copy the license file to another computer and nothing happens, which is the point.

Get a new computer, and you move the license over yourself, free of charge.

A second computer would like a second license.

And who keeps an eye on us? Staff powers are licenses too, all chained to a single hardware key.

Staff can cancel a license only while it is still refundable, and only with an owner's approval.

Once your license is private, only you can revoke it.

The keys that sign licenses are replaced every few months, and your apps trust a new one only after an owner has approved it.

Now, the limits, which have the decency to cost us rather than you. Someone who rewrites the app can make it skip all of this,

and a computer too old to have a security chip keeps its key where a determined person could copy it.

Either way, that is a sale we did not make.

And if our website were ever taken over, the intruder would find no names, no addresses, and nothing that ties a license to the person who bought it.

They could hand out free licenses until we noticed and retired the key.

Annoying for us. Uneventful for you.

As of October 2026, some of this is built and tested, and some is still on the drawing board. The page below says which, piece by piece.

That concludes this entry. The next one concerns how Cody keeps your computer yours.

Status on October 1, 2026: nothing described here is in a customer’s hands yet. The site’s side and the web client’s check are written and tested in code; the Mac app’s side is being written. No signing key exists, nothing sells a license, and no app requires one: the web client asks a Mac for its license and only records the answer. Every diagram and every table row below says which of three states it is in.

The design changed on October 1. In the first version (stage 1) the buyer’s browser made the licenses and a website passkey owned them. That path exists in code, with tests, and is being retired, because a page on the site’s domain can always ask a website passkey for its key — and whoever takes over a site decides what its pages do. In the current design the Mac app makes and holds the license: its code is signed with a key no web server holds, and macOS checks it before it runs. Everything the Mac app does in that design is tagged Designed below. The site’s and the web client’s side of it is built and tested — services/www/test/license-mac.test.mjs makes the Mac app’s calls the way the app will — and is tagged Built, as is what stage 1 built and the current design still uses.

On this page

  1. Buying
  2. Going private automatically
  3. Checking a license offline
  4. Revoke, move, and the two lists
  5. Staff powers are licenses too
  6. Signing keys
  7. What the site can connect
  8. Who could attack it, and what they get
  9. Test evidence
  10. Not built yet

What it is made from

No cryptography here is our own. These are the parts, by their names.

PartWhat is usedStatus
The signature on a licenseRSA blind signatures, RFC 9474, variant RSABSSA-SHA384-PSS-Randomized, through Cloudflare’s @cloudflare/blindrsa-ts 0.4.6 (pinned to that exact version). Checking one is ordinary RSASSA-PSS with SHA-384.Built
Key sizeRSA, 3072 bits by default (about 128-bit strength); 4096 is accepted too. A new key each quarter is what limits a leak, not the size.Built
The owner keyEd25519. One random key pair per license, made by the Mac app and kept in the Keychain (synced through iCloud Keychain); every use asks for Touch ID or the Mac’s password first (LocalAuthentication). The site checks its signature on a conversion order and on a revoke against the key inside the license.Built the format, the site’s checks
Designed the Mac app’s keys
The Mac keyECDSA with P-256 and SHA-256. The public half is a field of every license, covered by the signature; a license without one is refused. To show that it holds a license, a Mac signs a fresh 32-byte challenge from the headset or browser, together with the license’s id and the Mac’s own identity key. As designed the private half is made inside one Mac’s Secure Enclave and cannot leave it; a Mac without a Secure Enclave keeps it in the Keychain, which is weaker.Built the field, the proof, the web client’s check
Designed the Mac’s keys and its answer, the headset’s check
Stage 1’s owner: a website passkeyWebAuthn, user verification required, with the PRF extension where the browser and authenticator have it; signatures ES256, RS256 or EdDSA. The private license’s owner key was derived from the passkey’s PRF output with HKDF-SHA-256 (Ed25519). Being retired for customers’ licenses; staff licenses keep their passkeys (section 5).Built — stage 1, being retired
Stage 1’s encrypted copy (the vault)AES-256-GCM. The key is HKDF-SHA-256 of the passkey’s PRF output on a second, separate input. The current design has no vault: the Keychain holds the license, and an encrypted owner backup file (a password you choose) is designed for Macs with iCloud Keychain off.Built — stage 1, being retired
Designed the backup file
Revocation list, customer licensesEd25519, signed by a key the site holds.Built
Staff licenses, the key list, the staff revocation listWebAuthn approvals (ES256, a P-256 key) that chain up to one hardware key whose public half is built into the apps.Built
What gets signedBytes with one rule: a version byte, then a fixed number of length-prefixed fields in a fixed order, and nothing after the last. No JSON is ever signed. A license’s message has seven fields; the Mac key is the seventh.Built
Relay passesSingle-use, blind-signed passes — the same blind-signature core; a pass is 1 GB of Cody’s relay. A license has nothing to do with the relay, and passes never come from showing one: a purchase comes with starter passes, and a relay subscription hands them out to draw keys. The earlier note for this named Privacy Pass tokens (RFC 9576–9578); the format is not settled.Built the format, the site’s signing and desk
Designed the Mac app’s side

1. Buying

The website takes the payment and hands the Mac app a one-time token; everything after that happens in the app. The first license from a purchase is signed in the open and recorded against the purchase. That is on purpose: a license signed blind cannot be found again by the site, so it could not be taken back. If the first license were private, a refund — or a charge on a stolen card — would leave a working license behind. So the first one is refundable, and the private one is prepared at the same moment and waits.

Figure 1. A purchase, step by step Built: the site’s side Designed: the Mac app, payment

A purchase, step by step Two lanes, the Mac app and Cody’s site. Payment at Stripe leads to a one-time credit, handed to the app by a page whose link carries the token. The app makes its keys and a refundable license, which the site reads, records and signs. The app also prepares a blinded private license and a conversion order, and sends nothing of it. Everything stays in the Mac’s Keychain and Secure Enclave. THE MAC APPOVER THE NETWORKCODY’S SITE 1 Pay Designed License › Buy… opens the website’s checkout (Stripe: a card and an email). The site reads neither of them. Stripe Designed webhook: paid + a purchase reference 2 One credit per payment Built A one-time token. The site stores only its SHA-256 and the purchase reference. Token to the app Built A page with “Open in Cody”. The token is in the link’s fragment, so in no request and no log. Today the only tokens are test ones. the token 3 Make the keys Designed Two owner keys (Ed25519) into the Keychain; two Mac keys (P-256) inside the Secure Enclave. One Touch ID for the whole claim. 4 The refundable license Designed A random 32-byte id, one owner key and one Mac key (public halves). token + the license, readable signature + the date it may go private 5 Read, record, sign Built Spends the credit in one statement, records license id ↔ purchase, and signs with the refundable key (RSA-PSS). 6 Prepare the private one Designed A new id, the other owner key and Mac key, blinded. The first owner key signs an order: “swap, but not before this date”. nothing is sentat this point The site sees none of this now. After the hold it is sent the blinded value and the order — never the license inside. 7 What the Mac keeps Designed In the Keychain: the license, the order, the blinded request and the secret that unblinds it — never in a file. The Mac keys’ private halves stay in the Secure Enclave. What the site keeps Built The token’s SHA-256, the purchase reference, the refundable license’s id. No key of either license, and nothing of the private one.

The diagram scrolls sideways.

Left: what happens in the Mac app. Right: what the site does and keeps. Middle: exactly what crosses between them. The right lane is code with tests: the credit, the page that hands the token to the app, and the claim — a refundable license owned by an Ed25519 key and naming a Mac key, read, recorded and signed (services/www/test/license-mac.test.mjs makes these calls the way the Mac app will). The left lane is dashed because the Mac app does none of it yet, and it registers no link of its own today. Payment through Stripe is not wired up; the only tokens are test ones, from a button on the admin site.

What this proves

  • One payment, one signature. The credit is spent in the same database statement that allows the signing; the same request sent again gets the same answer, and anything else on a spent credit is refused.
  • The site can refund: it holds the refundable license’s id next to the purchase reference.
  • Nothing of the private license reaches the site at purchase. The test captures every request of the claim, dumps every table and keeps every log line, and looks for the private license’s id, owner key and Mac key in all of it.
  • The claim carries no cookie and names no Mac, room, device, invite or board identity; the keys in the refundable license are read and not stored.

What it does not

  • A refundable license is matched to its payment: the site keeps its id beside the purchase reference (and reads the two public keys in it), and holds nothing about the person. Stripe holds the email and card behind that reference. The match is what makes a refund possible, and it ends when the license becomes private.
  • The Mac app’s side is designed, not built: the keys in the Keychain and the Secure Enclave, the app making either license, the app opening from the link. In the test the Mac’s part is played by the test itself, with keys made in software.
  • Stage 1, being retired: there the blinding ran in JavaScript that the site serves, and the owner was a website passkey. A site that served altered code at the moment of purchase could record what the browser made, and a page on its domain could ask the passkey for the owner key. Nothing let a buyer check the code they were served. The Mac app’s code is signed with a key the website does not hold and is checked by macOS before it runs.
  • Stage 1’s vault, being retired with it: its row keeps the passkey’s public key — a stable handle — and the first write to a row is not authenticated: someone who knows a credential id could occupy the row first (16 KB and 20 writes an hour per address bound it).

Figure 2. What “signed blind” means Built Designed: the Mac app doing it

A blind signature in five steps On the Mac: the license message is mixed with a random number. The site signs the blinded number. Back on the Mac the random number is divided out, leaving an ordinary signature on the license, which the site never saw. ON YOUR MACAT CODY’S SITE 1 The license a random 32-byte id+ the owner’s public key+ the Mac’s public key= the message m 2 Blind it Mix m with a randomnumber r (RFC 9474).r stays on the Mac. 4 Unblind Divide r back out. Whatis left is a signatureon m itself. 5 A private license It checks out under thepublic key like anyRSA-PSS signature.Nothing in it says whichrequest it came from. the blinded number + token + key id the blind signature 3 Sign what arrives Spends the token in one statementand signs the blinded number withthe private key. One signatureper credit. The site sees the token, a key id, and one numberthat looks random. The site never sees the id, the keys in the license, or thefinished signature.

The diagram scrolls sideways.

The site signs a number it cannot read. When a private license is shown to it later, the signature is valid — and it matches none of the blinded numbers the site remembers signing. Blind signing is built and tested end to end in JavaScript and the Worker, for a license that names a Mac key too; the Mac app doing steps 1, 2 and 4 is designed.

What this proves

  • By content, a private license cannot be matched to the request that produced it. The blinded number is independent of the license, and so are the two things the site keeps from a conversion (a hash of the request, the blind signature).
  • Checking the result needs nothing special: it is an ordinary RSA-PSS signature.
  • After a blind issuance the test dumps every table and looks for the license’s id, its owner key and the credential id. None is there.

What it does not

  • That nobody can forge. That rests on an assumption (RSA one-more-inversion, RFC 9474 §7): from n signatures nobody can make n + 1. So every signature has to be a paid one — the single-statement spend, one way of signing per key, and a count of signatures per key against credits spent.
  • Anything about timing or network addresses. See section 7.
  • Anything about who holds the private key. Whoever has it can sign as many licenses as they like. See section 6.

2. Going private automatically

Privacy that has to be asked for is not much privacy, so the exchange is the default. The order for it is signed by the refundable license’s owner key when the license is made, under the same Touch ID; after the hold nobody has to approve anything again. “Keep it refundable” is a choice for whoever wants it: the order is simply not sent.

Figure 3. From refundable to private, and the keys of each Built: the site’s side Designed: the Mac app’s part

From a refundable license to a private one Three phases: a refundable license during the hold, the conversion when the prepared order is sent, and the private license afterwards. Below: the Mac app makes four keys at purchase. The refundable license carries one owner key and one Mac key, which the site reads; the private license carries the other two, which travel only inside the blinded request. Stage 1 used a website passkey instead. DAY 0 TO THE END OF THE HOLDAFTER THE HOLD, WHEN NEXT ONLINEFROM THEN ON Refundable license Built Signed as the site read it. The siteknows its id and its purchase, andhas read the public keys inside it. You — or staff, see section 5 — canrevoke it. That is what makes arefund possible. Hold: 14 days. Conversion Built The prepared order is sent, with noprompt. The site checks the ownerkey’s signature on it and the date, puts the refundable id on therevocation list and signs the blindedrequest — in one database batch. Private license Built Unblinded by its maker. A new id andnew keys. The site has no record ofit and cannot find it. Only its owner’s key can ask for arevoke. The purchase can no longerbe refunded. THE KEYS OF EACH LICENSE The Mac app Designed makes four keys atpurchase, after oneTouch ID. No two arerelated, and none isthe identity key thatrooms and devicesknow the Mac by. Owner key 1 Ed25519, random; keptin the Keychain Mac key 1 P-256; made in theSecure Enclave In the refundable license Built the site reads both public halveswhen it signs, and stores neither Owner key 2 Ed25519, random; keptin the Keychain Mac key 2 P-256; made in theSecure Enclave In the private license Built both public halves travel onlyinside the blinded request, so thesite is sent neither Stage 1, built and being retired: the owner was a website passkey, and the private license’s owner key was derived from it (PRF, HKDF-SHA-256) or was a second passkey. It had no Mac key.

The diagram scrolls sideways.

Top: the three phases. Bottom: the two licenses of one purchase carry four unrelated keys, so no key appears in both. Built, with tests in services/www/test/license-mac.test.mjs: a license that carries an Ed25519 owner key and a Mac key, the site converting on an order that owner key signed, and the search showing that the private license’s keys reach the site in no request. Designed: all of the Mac app’s part — making the four keys, signing the order, sending it by itself at a random moment within three days of the date, unblinding the answer, one notice. Its Swift code is being written.

What this proves

  • The order cannot be reused for anything else. What the owner key signed is a hash of the refundable id, a hash of the blinded request, the not-before date and the key id; a changed date, another blinded request or another key’s signature is refused.
  • The hold is the site’s to enforce: it refuses before the later of the order’s date and first issue + hold. Raising the hold later delays an order; it does not break it.
  • The two licenses share no owner key, no Mac key and no id, and neither Mac key is the Mac’s identity key — checked on every captured request, every table and every log line.

What it does not

  • The site knows that a given refundable license was converted, and when. The request comes from some address; the site stores none (rate limits use a keyed, daily-changing hash), but Cloudflare’s edge sees requests. Designed against the timing: the app sends the order at a random moment within three days, on a fresh connection with nothing else in the request.
  • That the keys are where the design puts them. The site sees public halves; it cannot tell a key in a Keychain or a Secure Enclave from any other.
  • Stage 1 only: one passkey gives one derived key, so a re-issued private license carries the same owner key as the one it replaces. The site never asked for that — a re-issue with a new owner key and a new Mac key is accepted, and tested — and the Mac app is designed to use new ones.
  • A Mac that never goes online keeps its refundable license. A card dispute after the conversion leaves the license alive — accepted.
  • An order names the signing key it was blinded for. After a key rotation the old key has to stay able to sign conversions, or a new order has to be made for the current key.

3. Checking a license offline

The Mac app, the headset app and the web client are meant to run the same check, from what is already on the device. The JavaScript one, for the web client, reads the current format and is held to a file of shared test vectors. The Swift one, for the Mac and headset apps, was built for stage 1’s format and is being brought to the current one.

Figure 4. The check, with no network Built: in the web client Designed: Swift, acting on the result

Offline verification Three things on the device — the license, the key list and the last revocation list — feed five checks: shape, which key, signature, not revoked, and the Mac’s signed answer to a fresh challenge. All pass: valid, and what it unlocks comes from the key’s entry. Any fails: not valid. A designed addition: a trial’s end date. ON THE DEVICETHE CHECK — NO NETWORKTHE RESULT The license a file, or one line of text thatstarts CODY-LICENSE-1 The key list public keys built into the app,plus entries an owner approved(the apps’ saved copy: Designed) The revocation list the last copy this device saw:signed by the site (Ed25519); itsversion can only go up 1 Shape Built a version byte, fixed fields in a fixedorder, nothing after the last one 2 Which key Built the key id is on the key list and hasnot been distrusted 3 Signature Built RSA-PSS with SHA-384 overprefix · message, under that public key 4 Not revoked Built the id is not on the revocation listthis device keeps Valid Built when all five pass. What itunlocks comes from thekey’s entry (which product,live or test) — never fromtext inside the license. Not valid Designed when any check fails.For now the apps onlyrecord it; a limitedmode comes with trials. ALSO CHECKED,OFFLINE 5 The Mac’s answer Built a fresh challenge, signed with theMac key named in the license A trial’s end date Designed a signed ticket, 14 days; the Macremembers the latest time it saw

The diagram scrolls sideways.

Everything the check needs is already on the device. The four checks and the Mac’s answer are code in the JavaScript reader, and the web client runs them when it connects to a Mac (services/www/test/license-mac.test.mjs; services/app/test/license-show.test.mjs for the client itself): it keeps the result, logs one line without the license’s id, and changes nothing on screen. The Swift reader for the current format, the Mac answering, the headset checking, what an app does with the result, and the trial check are design.

What this proves

  • No network is involved: the answer follows from three things on the device.
  • A license means what its signing key says. A test license that calls itself “everything-forever.enterprise” is a Mac license; a license under a test key is a test license whatever it says.
  • The owner is no part of validity. Only the site’s owner actions look at the owner key.
  • A license is accepted only from the Mac that holds its Mac key. The answer is checked against the key inside the license, the Mac identity key the client pinned when it paired, and the client’s own fresh challenge — so an answer from another key, or one relayed from another Mac, fails.

What it does not

  • That the Mac key is in the Mac’s hardware. Nothing lets a client tell a Secure Enclave key from a software one; where the key is in software, a copy of the license together with its key passes this check (section 8).
  • That anything answers. No Mac app answers the challenge yet, so today the web client records “no answer”; and the Swift reader has not followed the current format, so the two readers no longer agree on one set of vectors.
  • That a revoke has arrived. A device knows the last list it saw; an offline Mac hears late, and a device that never saw a revocation can be handed an older, validly signed list.
  • That the check runs. An app with the check patched out runs without a license. The code is not obfuscated, and this cannot be prevented.

4. Revoke, move, and the two lists

A license is made for one Mac. To replace it, or to move it to another Mac, its owner re-issues it: the old id goes on a list every device checks, and a new license is signed blind in its place. The proof of ownership is checked against the key inside the license itself, so the site does not need to know who the owner is.

Figure 5. The owner replaces or moves a license; the two revocation lists Built: the site’s side Designed: the Mac app’s side

Revoke and re-issue, and the two revocation lists Four steps: the site hands out a one-use challenge; the owner proves ownership with the owner key from the Keychain, after Touch ID; the site checks the proof against the key inside the license, revokes the id and mints one credit; the Mac app uses the credit for a new blind signature, for this Mac or the one the license is moving to. Below: the customer list is signed by the site; the staff list is approved by an owner’s key. SITEMAC APP + OWNER KEYSITEMAC APP + SITE 1 Challenge Built The site hands out aone-use nonce, good for2 minutes. It names nolicense and no action. 2 Prove it Designed Touch ID, or the Mac’spassword, unlocks theowner key in the Keychain.It signs the challenge(Ed25519). 3 Check, revoke Built The license’s signature,then the proof against thekey inside the license. Idonto the list; one newcredit, in the same batch. 4 Re-issue Designed The credit pays for oneblind signature: a new id,a new owner key, and theMac key of this Mac or ofthe one it is moving to. THE TWO REVOCATION LISTS Customer licenses Built Signed by the site’s list key (Ed25519). An id gets on it by: the owner’s revoke · a conversion (therefundable id) · a staff revoke of a refundable license. Ids are never removed and the version is their count, so itonly grows. A device refuses a list older than the one it has. The limit: whoever holds the list key can add any id theyknow, or serve a shorter list with a higher version. An offline device hears of a revoke late. Role licenses (staff) Built Approved by an owner’s key, through the chain of approval upto the anchor built into the apps (section 5). The site stores the list but cannot change it: a row itwrites by itself is skipped, and the apps refuse it. A revoked owner cannot sign itself back in; ids never leave;an older list is refused. A role license’s id on the site-signed list means nothing;this list says nothing about a customer’s license.

The diagram scrolls sideways.

Top: one Touch ID replaces a license, or moves it to another Mac. The site’s side is built and tested for an owner that is an Ed25519 key (services/www/test/license-mac.test.mjs): the revoke, the one credit, and a re-issue with a new owner key and a new Mac key, which the site does not compare with the old ones. The Mac app’s two steps are designed. As designed, owner actions happen only on the owner’s Macs, never in a browser — stage 1’s web page for them, with a website passkey, is built and being retired. Bottom: two lists with two different signers. The site signs the customer list because conversions and owners’ revokes add ids when nobody is at a hardware key.

What this proves

  • Through the site’s API, only the holder of the owner key can revoke a private license. Staff cannot: they can cancel a license only while it is still refundable, their revoke looks up refundable licenses, and a private one has no row. No staff power over private licenses exists or is planned.
  • One revoke mints exactly one credit, in the same batch. A second revoke of the same id fails and mints nothing.
  • The site cannot revoke a staff license, and cannot take a staff revocation back.

What it does not

  • “Only the owner can revoke” is a statement about the site’s API and its staff. The customer list is signed with a key the site holds: whoever controls that key can list any license id they have seen, or un-revoke one.
  • To revoke or move a private license its owner shows it to the site, which then sees its id and the two public keys in it; it keeps the id, on the revocation list, and neither key. The call carries no cookie and names no Mac or room, and a replacement with a new owner key and a new Mac key is in no request and no table: the site knows that the revoked license was replaced, and cannot tell what it became (tested). Stage 1 only: there the replacement carries the same owner key, so the two can be tied to each other, though not to a purchase.
  • Stage 1 only: after a re-issue the page replaces the vault copy, seconds later and from the same address. The two requests share no value, but the timing is a guess at which passkey — and so which purchase — the license belongs to. The current design has no vault.
  • A revoked license keeps passing on a device until that device gets a newer list. After a move, the old Mac’s copy works until the list arrives.
  • Whoever holds a license and its owner key can move it — that is what the owner key is for. On the owner’s Mac the key is designed to come out of the Keychain only after Touch ID or the Mac’s password.

Another Mac of yours Designed

It sees the owner keys through iCloud Keychain and offers two things: move the license to this Mac — a re-issue; the other Mac’s copy stops when it next sees the list — or buy a license for this Mac. A second Mac is a second license; moving is free.

iCloud Keychain off Designed

The owner keys live on that Mac only. The app’s License page says so and offers an encrypted owner backup file, locked with a password you choose. Share License… saves the license itself; that file works nowhere by itself.

Lost the Mac, and no copy of the owner key Later

The license was bound to that Mac’s hardware, and nothing is left that can move it. There is no automatic way back, on purpose: re-issuing from a receipt could leave the old license alive. It would be handled by hand.

Stage 1: lost the file, kept the passkey Built

Being retired. Sign in with the passkey; the site returns the encrypted copy and the browser opens it. This needed PRF: without it there was no vault copy.

5. Staff powers are licenses too

Admin rights are not rows in a table the website could edit. Each one is a role license. It is approved through a short chain that ends at a hardware security key held by the business owner, and it is usable only together with its holder’s own passkey. Role licenses are not blind: they are meant to be known and revocable.

Figure 6. The chain behind a staff power, and who can cancel a refundable license Built Designed: the dashboard screens

Role licenses, and who can cancel a refundable license Left: the anchor, a hardware key’s public half built into the apps, approves an owner license, which approves a role license; at most three links. Right: a billing admin’s revoke is pending until an owner approves it; only refundable licenses can be revoked; every step writes an audit row. THE CHAIN OF APPROVAL — IT TRAVELS INSIDE THE FILE The anchor Built The public half of a hardware security key (P-256), builtinto the apps. The private half is on no server or disk. approves: WebAuthn, over a hash of the license An owner license Built A role license holding “owner”, bound to its holder’spasskey. An owner can approve another, e.g. a backup key. approves A role license Built admin-billing · admin-support · developer · tester ·facecheck. Names its holder’s passkey, a label, an expiry. At most 3 links. Each link must be in date and not on theowner-signed role list. A revoked or expired owner takeseverything it approved down with it. On the site the file alone does nothing: each action alsoneeds a fresh approval from the holder’s passkey. A STAFF CANCEL NEEDS AN OWNER 1 A billing admin asks Built Role license + a fresh passkey approval over a nonce boundto this action and this purchase. The result: pending. waits up to 7 days, then lapses 2 An owner approves Built With an owner’s key; the approval covers the hash of therequest. An owner (today, only the founder) cancels directly./text> 3 The refundable license is revoked Built Only a refundable one: a private license has no row tofind. Unspent credit of that purchase is withdrawn. every step writes a row The audit log Built Which role license, what, the target, the reason, when.Rows are only added. The screens to read it: Designed.

The diagram scrolls sideways.

Left: why a role license can be trusted with no server involved. Right: what a staff revoke takes — and it reaches a license only while that license is still refundable. Once a license is private, only its owner can revoke it: no staff power over private licenses exists or is planned. The endpoints, both readers and the page that makes role licenses are built; the dashboard screens for pending revokes and the audit log, a daily cap on revokes, and app-side unlocks for testers are designed.

What this proves

  • A taken-over website cannot make an admin: every role license chains to a hardware key whose private half is on no server.
  • A copied role license does nothing by itself, and the admin token alone authorizes nothing: each privileged request needs the license and a fresh passkey approval bound to that action and its target.
  • Staff can cancel a license only while it is still refundable, and a billing admin cannot do it alone: an owner approves it. Once a license is private, only its owner can revoke it: no staff power over private licenses exists or is planned.

What it does not

  • That an owner’s key is safe. Whoever holds an owner’s key and can unlock it has an owner’s powers. Another owner can revoke that owner license; if the anchor itself is lost with no second key enrolled, the apps need an update with a new anchor.
  • No anchor is enrolled today: the built-in list is empty until the first one is made.
  • The audit log is a table in the site’s database, not a signed record; the reason text in it is not covered by the approval; and a list’s date is its signer’s word.
  • The site itself goes by its own database for staff revocations. Whoever can roll that database back can make the site forget one — the apps still refuse.

6. Signing keys

What a license means comes from the key that signed it, so the keys are the thing to protect. There is one key per product, per mode (live or test) and per quarter. Each key signs one way only: a blind key never signs anything it has read, and the others never sign blind.

Figure 7. Quarterly keys, how a key becomes trusted, and what happens if one leaks Built Designed: the signer, re-claim, alarms

Signing keys A timeline of quarterly keys: each signs during its quarter and keeps verifying afterwards. A new key is made, approved by an owner’s key, and only then trusted by the apps. If a key leaks, an owner distrusts it; re-claiming and alarms are designed. ONE KEY PER QUARTER — THE IDS ARE EXAMPLES; NO KEY EXISTS YET Built 2026 Q42027 Q12027 Q22027 Q3 mac-perpetual.live.2026q4 mac-perpetual.live.2027q1 mac-perpetual.live.2027q2 signs new licenses still verifies: a license under an old key stays valid A NEW KEY JOINS THE LIST 1 The key is made Designed Designed: inside a separate signerWorker, where no person sees it.Today: made on a developer’s Macand set as a Worker secret. 2 An owner approves Built A list entry — add, key id, publickey, date — approved with anowner’s key. The site keeps it onlyif the approval verifies. 3 The apps trust it Built Built-in keys plus approved entries.Each reader checks the approvalagain and ignores any entry thewebsite wrote by itself. IF A SIGNING KEY LEAKS Distrust Built An owner signs “distrust key K fromdate D”. Readers stop accepting K,so forged and genuine licensesunder it all fail. Re-claim Designed Each purchase of that quarter getsone new signing credit through itsStripe receipt; the Mac app gets anew license signed blind. Counting Designed Signatures per key must equalcredits spent. The counters arebuilt; the alarm and the automaticpause are not.

The diagram scrolls sideways.

Top: key ids carry their quarter, and readers keep every past public key, so a rotation invalidates nothing. Middle: the website cannot add a signing key by itself. Bottom: the emergency path. The key list, the approval check and distrust are code in the site and both readers; the signer Worker is an interface only, and no key of any kind has been made.

What this proves

  • The website cannot make the apps trust a new signing key. Tested: a row written straight into the table is served, and both readers ignore it.
  • Rotating keys needs no app update and breaks no existing license.
  • A leaked key can be shut off without an app update, and the damage is one quarter’s licenses.

What it does not

  • As built today, private keys would be Worker secrets created on a developer’s machine. Anyone who can read those secrets, or deploy code to the site, can sign. The signer Worker that would generate keys inside itself is not built.
  • Even with the signer, code deployed to it could read its storage. What is planned against that: a tiny surface, its own deploy token, two-factor on the account, and the count above.
  • Distrust cannot tell forged licenses from genuine ones under the same key — they are blind — so genuine holders lose theirs until they re-claim, and re-claim is not built.
  • Offline devices hear of a distrust late. The apps’ saved copy of the key list is not built.

“The site” here means the website’s server as built, plus anyone who controls it and chooses to log more than the code does. “By content” means from values stored or sent; timing and network addresses are separate rows because they are a different kind of evidence.

Two thingsCan the site connect them?WhyStatus
A payment ↔ its refundable licenseYes, on purposeThe license id is recorded with the purchase reference so the purchase can be refunded. Stripe holds the email and card behind that reference; the site reads neither.Built
A refundable license ↔ the fact and time it went privateYesThe site performs the conversion and marks the purchase.Built
A refundable license ↔ the private license it became, by contentNoSigned blind; a different id, a different owner key, a different Mac key. What the site keeps from the conversion is independent of the final license. Tested: the private license’s id and keys are in no request of the claim or the conversion, in no table and in no log line.Built
A payment ↔ a private license, by contentNoFollows from the row above: a private license has no row in any table. Staff can cancel a license only while it is still refundable; a private one only its owner can revoke, and no staff power over private licenses exists or is planned.Built
The same two, by timing and addressA guess, for a site that logsThe conversion arrives from the Mac’s address, and a private license shown to the site later from the same address is a guess anyone could make. The site’s code stores no address; Cloudflare’s edge sees every request. Designed to leave less to guess from: the app converts at a random moment within three days, on a fresh connection with nothing else in the request, and a private license is shown to the site only for an owner action or an update check.Built — open weakness
Designed the random moment
A private license ↔ its replacement after a re-issue or a moveNo, by content, when the keys are new. Stage 1’s page: yes, if shown bothThe site does not ask that a replacement keep the old keys: one with a new id, a new owner key and a new Mac key is in no request and no table (tested), and the Mac app is designed to make it that way. Stage 1’s web page re-derived the same owner key for the replacement.Built the site’s side
Designed the Mac app
Built — stage 1’s page, being retired
A license ↔ a MacNo, at the siteA license names a Mac key, but that key belongs to this one license: the refundable and the private license get two unrelated ones, and neither is the identity key that rooms and devices know the Mac by. The proof that a Mac holds its license is asked for by a headset or browser over the direct channel, never through a call to the site. Tested: no stored row and no log line holds a license id beside an address, a room, a device, an invite or a board identity, and the Mac’s identity key is never sent.Built the site, the web client
Designed the Mac app, the headset
A private license ↔ its update checksAs designed: yesA licensed Mac would show its license when it checks for an update, with an install number — a random value made on that install, mixed with the license id so it means nothing anywhere else. Per license id the site would keep the first install number and a count of different ones seen in 90 days: the id is seen at an address at that moment, and the address is not stored. It is not linkable to the buyer, a room, a device or use of the relay. This is the one routine call that carries a license; it exists to notice copies (section 8).Designed
A license ↔ use of the relayAs designed: noA license has nothing to do with the relay. The relay takes single-use, blind-signed passes, and passes never come from showing a license: a purchase comes with starter passes, signed blind in the claim against the same one-time token, and a relay subscription hands them out to draw keys. The site would know that a purchase got starter passes, and could not recognize one when it is spent.Designed
A relay subscription ↔ a licenseAs designed: noA subscription has draw keys, one for each Mac allowed to use it, and no license ids. The site would see a Stripe customer, a count of Macs and how many passes each key drew — never a license, a room or a device.Designed
One relay session ↔ anotherAs designed: yes within one relay tab, no beyond itPasses are paid into a tab — a random id only that Mac knows, dropped when it is empty or 30 days old. Use is linkable within a tab, and not to the license, the subscription or the next tab. Addresses and timing remain what they are.Designed
A license ↔ a board identity (points, votes)NoA license reaches the site in three calls only — the conversion, an owner action, and as designed the update check — each with no cookie and no room. Tested for the first two: the rows that name a person hold no license id, and the rows that hold a license id name nobody. Starter points would come as a separate blind-signed voucher, redeemable into any identity.Built the two calls
Designed the update check, vouchers
A trial ↔ a MacAs designed: yesA trial ticket is signed in the open and names the Mac’s identity key. One per Mac is kept by Apple’s DeviceCheck (a per-device flag at Apple), with a hash of the hardware id as the fallback.Designed
A role license ↔ a staff memberYes, on purposeRole licenses are not blind. The label, the roles and the holder’s passkey are in the signed message, and every action is logged under the role license’s id.Built
Stage 1 only: a refundable license ↔ its vault copyYesThe vault row holds the passkey’s public key, which is also inside stage 1’s refundable license. The current design has no vault.Built — stage 1, being retired
Stage 1 only: a private license ↔ a passkey, at re-issueA guess, by timingThe vault copy is rewritten seconds after the revoke, from the same address. No value is shared between the two requests. The vault write can be skipped.Built — stage 1, being retired

What the site keeps in general — devices, the board, payments — is on What Cody stores.

8. Who could attack it, and what they get

AttackerWhat they getWhat stops or limits itStatus
Someone with a stolen license file, a cloned disk, or a leaked owner keyA license whose signature checks out anywhere.A client accepts a license only together with a fresh challenge signed by the Mac key the license names. Tested in the web client: not from another key, not from the Mac’s identity key, not for another Mac’s connection. As designed that key’s private half is made inside one Mac’s Secure Enclave and cannot leave it, so a file, a disk image or an owner key does not contain it and the license runs on no other Mac. No Mac app answers the challenge yet, and the headset’s check is not built.Built the proof, the web client’s check
Designed the Mac’s key and answer, the headset
A shared license (posted in public)The same file, in many hands.It answers a challenge on the one Mac it was made for. A second Mac is a second license; moving to a new Mac is the owner’s re-issue, and the old license goes on the revocation list. The relay is no part of a license, so sharing one shares no relay use.Built the proof, the re-issue at the site
Designed the Mac app
A Mac key that is not in the Mac’s hardwareA Mac without a Secure Enclave keeps its Mac key in the Keychain instead, and nothing lets the site or a client tell a hardware key from a software one. A license whose key is in software can be copied together with its key, and every copy passes an unmodified client’s check.This is a limit, and it cannot be prevented offline. Designed against it: a licensed Mac shows its license when it checks for an update, and the site counts, per license id, how many different installs it has seen in 90 days. The first install keeps getting updates from that check; any other is told the license is in use on another Mac, with the choice to move it there (which takes the owner key) or buy one. That takes automatic updates away from casual copies and shows that a license is being passed around. It does not stop a determined copier: the update file is the same for everyone, and a patched app can skip the check. It gives nobody new powers: a private license is still revoked only by its owner, and no staff power over private licenses exists or is planned.Designed
A patched appThe Mac app running with the license check removed.This cannot be prevented, and the code is not obfuscated. The answer is the check in the official headset and web clients, which a patched Mac app cannot skip for them — and the relay costs passes whichever app asks.Built the web client’s check
Designed the headset’s, the apps acting on it, passes
A leaked signing key (blind)Any number of licenses nobody can tell from real ones.An owner’s distrust entry ends everything under that key; quarterly keys bound it to one quarter; signatures per key are counted against credits spent. Genuine holders would need to re-claim.Built distrust, counters
Designed alarms, re-claim
A leaked refundable signing keyRefundable-kind licenses the site has no row for, so staff cannot find them to revoke.Distrust, as above.Built
A leaked list keyThe power to un-revoke a customer’s license (a shorter list with a higher version), or to list any id they know.Customer licenses only: staff licenses are on a list an owner signs. A device refuses a list older than the one it keeps.Built
Someone who takes over the websiteThe database, the Worker’s secrets — today that includes every signing key — and the pages the site serves.They cannot: find a private license (none is stored), connect one to a purchase by content, make an admin, add a signing key the apps accept, or take back a staff revocation. They can: sign licenses until the key is distrusted, change the customer revocation list, and log addresses and timing from then on. As designed they cannot touch how a license is made: that happens in the Mac app, whose code the website does not sign. The page that hands the token to the app makes no license and sends the site nothing.Built
Designed the license made in the Mac app; keys out of the site’s reach
The same, against stage 1’s web pathThe page that made licenses in the buyer’s browser, and the domain the owner passkey belongs to.Nothing limited it: altered code could record what the browser made, and a page on the site’s domain can always ask a website passkey for its key. This is why that path is being retired and is linked from nowhere.Built — stage 1, being retired
A dishonest adminA billing role: the power to ask for the revoke of a refundable license.The request waits for an owner’s approval and lapses after 7 days. Staff can cancel a license only while it is still refundable; once it is private only its owner can revoke it, and no staff power over private licenses exists or is planned. Every act is an audit row. A daily cap on revokes is designed.Built
Designed cap, screens
Someone holding only the admin token, or a copied role licenseA request that reaches the admin API.Nothing is authorized without a role license and a fresh approval from its holder’s passkey.Built
A buyer with a stolen cardA refundable license.During the hold the license can be revoked and the charge refunded. After the conversion there is nothing to revoke; a dispute then leaves the license alive.Built hold, revoke
Designed Stripe side
Trial farmingRepeated 14-day trials.One trial per Mac through Apple’s DeviceCheck, which survives reinstall and erase; where that is unavailable (older Intel Macs, virtual machines), a hash of the hardware id instead. A daily cap, and a switch to turn trials off or require a card. A wound-back clock is caught by a latest-time-seen mark.Designed
An owner whose Mac is lost or deadNot an attack. With iCloud Keychain, or the owner backup file, the owner key is still theirs and the license can be moved to another Mac.With neither, nothing is left that can move the license. No automatic recovery, on purpose. By hand, if it happens.Designed the move
Later by hand
Stage 1 only: someone who knows a passkey’s credential idThey can write the vault row for it before its owner does.16 KB per row and 20 writes an hour per address. The owner still holds the license file. The current design has no vault.Built — stage 1, being retired

9. Test evidence

All tests use throwaway keys made in the test and a software passkey that produces real WebAuthn data. The counts are from a run on October 1, 2026. None of them runs the Mac app or the headset: where a test needs a Mac, the test plays it, with keys made in software.

TestWhat it pinsChecks
services/www/test/license.test.mjsThe byte format; blind issuance end to end (blind, sign, unblind, verify offline); one signature per credit; a license means what its key says; a refundable license is recorded, a private one leaves no trace in any table; rate limits.60
services/www/test/license-owner.test.mjsRevoke and re-issue for both kinds of owner key; the conversion order and its hold; the staff refund revoke; the vault; the site-signed revocation list.101
services/www/test/license-browser.test.mjsThe buyer’s browser code itself, run against the site. It captures every request the page makes and dumps every table, then searches all of it for the private license’s owner key — as written and inside anything base64url or hex, three levels deep — with the passkey’s own key as the control that the search finds what is there. With PRF and without.57
services/www/test/license-roles.test.mjsRole chains; the admin token alone revokes nothing; a role license is nothing without its passkey; the two-step revoke; audit rows; owners make owners, three links at most; the owner-signed role list; the site-signed list has no say over a role; the site cannot take a role revocation back.79
services/www/test/license-keys.test.mjsSignatures counted per key; a key joins the list only with an owner’s approval; a distrusted key’s licenses all fail; a revoked owner’s entries fall with it.38
services/www/test/license-mac.test.mjsThe Mac app’s side of a license, as plain requests with no cookie: the claim, the order approved by an Ed25519 owner key and its hold, revoke and re-issue as a move to another Mac with new keys, the page that hands the token to the app, a client’s check of the Mac’s answer. And what the site must never connect: every request is captured, every table dumped and every log line kept, then searched — as written and inside anything base64url or hex, three levels deep — for the private license’s id and keys, and for a license id beside an address, a room, a device, an invite or a board identity.64
services/app/test/license-show.test.mjsThe web client asking a Mac for its license: a fresh challenge out, the answer checked offline against the pinned identity key, the result kept and logged in one line that never holds the license’s id.passes; not counted here
tools/tests/license-vectors.jsonThe shared vectors, public halves only: 18 licenses good and bad, 9 site-signed lists, 15 role chains, 18 role lists, a conversion order with the private license it becomes, the key list, and the derived owner key (pinned, because changing the derivation would lock every owner out).—
tools/tests/license.mjsThe JavaScript reader against those vectors.155
tools/tests/unit-license.swiftThe Swift reader (the Mac app’s and the headset’s) against the shared vectors, including unblinding. Written for stage 1’s format; it is being brought to the current one, with the Mac key, and until then does not pass against the current vectors.in progress
A real browser, driven by handThe /license/ page on a local server in a headless Chrome with a virtual authenticator, twice — with PRF and without — and the page that makes role licenses, once. Not part of the automated run. Not tried in Safari.by hand

What the tests cannot show: that a deployed site behaves like the tested code, how real authenticators and Safari behave, and anything about parts tagged Designed or Later.

10. Not built yet

Going the other way: stage 1’s web page for making a license, its website passkey as owner and its vault are built and tested, and are being retired. They stay in the code, linked from nowhere, until the Mac app’s path has been tried; then they go.