When you ship licensed desktop software, there is one decision you cannot undo: the address that validates the licence gets compiled into the binary.
The client pastes it once into their terminal settings and never touches it again. If that address ever stops existing, every binary in the world stops working at once.
The entire architecture follows from that.
The key decision: do not compile against your provider
The API lives on Supabase Edge Functions. The natural move would be to compile the Supabase URL straight into the binary. That ties your product to Supabase continuing to exist and continuing to maintain that function, forever.
Instead we put CloudFront in front and compiled against our own domain.
Migrating providers becomes changing the origin of a CloudFront distribution. No client finds out, and not a single installed terminal has to be touched.
It is the oldest indirection principle there is, applied to the one point in the system you cannot change later. The rest of the architecture is negotiable; that one is not.
There is a secondary benefit: Supabase's custom domain is a paid add-on per project. CloudFront in front is cheaper and decouples better.
Fail closed, not open
The secrets — the key that signs responses and the admin token — live in environment configuration, never in the repository.
The part worth attention is what happens when one is missing:
- Without the signing key, the validation endpoint answers 503.
- Without the admin token, the management endpoint answers 401 to everything.
Deliberate. The default failure mode of a lot of code is to degrade toward "everyone gets in" or, worse, to sign with the empty string. A missing secret must leave the system closed, not open. It is a three-line guard at startup and it is the difference between a misconfigured deploy and a breach.
Offline grace: the uncomfortable balance
The software runs on client machines with connections that drop. If validation is strict, a ten-minute network outage locks a legitimate client out of their product mid-session.
If it is lax, the licence is worthless.
Our point: 72 hours of grace, announced by the server rather than hardcoded in the client. Having the server decide the period matters — it lets you tune it without recompiling anything, and stops a client extending it by editing their copy.
Responses are signed with the shared key, which is also compiled into the binary. Without a signature, anyone could stand up a fake server on localhost and answer "valid" to everything.
The dashboard, and why it is private
The admin console is a static site in a private bucket, served only through CloudFront. Direct bucket access returns 403 — verified, not assumed.
The admin token is kept in sessionStorage: it clears when the tab closes, never touches disk and never travels anywhere except to the API itself.
A practical detail: we used the older origin-identity mechanism rather than the modern one because the installed CLI was from 2022 and did not know the new one. The bucket is exactly as private. Verifying the outcome matters more than using the fashionable primitive — and verifying it was one request to the bucket that returned 403.
What we took away
The real value in this design is not the provider choice, it is having identified which decision was irreversible before making it. Almost everything in an architecture can be changed later. What ships compiled into binaries sitting on other people's machines cannot.
That list is usually short. It is worth writing down explicitly at the start.
From the Cerberus licensing system at Tuurt Labs. Need an architecture like this? Write to support@tuurt.com.