Ed25519 Entitlements for License Validation
KeyRing AI validates licenses server-side, then returns a short-lived Ed25519-signed entitlement envelope the desktop can verify locally.
Most license systems stop at a database check. KeyRing AI does the database work too, but it does not make the desktop trust a loose API response. The website validates the license, binds it to a machine, checks status and billing state, then signs a short-lived Ed25519 entitlement envelope that the desktop verifies locally before allowing provider calls.
- The website still validates the license server-side: format, rate limits, license status, subscription status, expiry, and machine binding
- Successful validation returns a signed entitlement envelope with Ed25519, not just an unsigned true/false response
- The desktop verifies the signature, issuer, audience, machine ID, and expiry before trusting the entitlement
- The entitlement is short-lived, so access can be refreshed without handing the desktop a long-lived bearer of trust
- Prompt content, provider keys, and AI responses are not part of the license validation path
Table of Contents
Why a database check is not enough
A server-side license lookup is necessary, but it is not the whole trust model. The desktop still needs a way to prove that the response it cached came from KeyRing and still belongs to the current machine.
- A plain JSON response can be replayed or altered if the client trusts it blindly
- A desktop app needs a local verification step because it cannot call the website before every single feature check
- A signed envelope lets the website make the decision once and lets the desktop verify that decision later
Most licensing systems are built around one question: does this key exist in the database? That question matters, but it is incomplete for a desktop product. A local app has to make authorization decisions while it is running, while it is refreshing state in the background, and sometimes while the network is unreliable.
If the website simply returned an unsigned response that said valid: true, the desktop would have to trust the transport and the local cache forever. That is not a strong enough boundary for a commercial desktop app. The better pattern is to let the server do the authoritative database work, then sign the result so the client can verify it without turning every local decision into a fresh database call.
That is the role of KeyRing's entitlement envelope. It turns a server-side licensing decision into a compact, verifiable artifact.
The KeyRing license validation flow
The desktop sends a license key and machine ID to the website. The website validates the license, applies rate limits and commercial state checks, binds the key to the machine when needed, and signs the entitlement returned to the app.
- Desktop sends license key plus machine ID to /api/license/validate
- Website checks rate limits, key format, license status, expiry, subscription state, and machine binding
- Website signs the entitlement claims with Ed25519 and returns the envelope to the desktop
The validation request is intentionally narrow. The desktop sends the license key and its machine ID. It does not send prompts, provider API keys, conversation content, generated files, or AI responses.
On the website, the license validation route applies multiple checks before anything is signed. It rate-limits by IP and by license-key plus machine-ID pair. It rejects invalid key formats. It looks up the license, checks that the license is active, checks expiry, verifies subscription state where a subscription exists, and enforces the machine binding rule.
If the license has not been bound yet, the first successful validation binds it to that machine. If it is already bound to another machine, validation fails and the user has to contact support to transfer it. That is the part that prevents a paid license from becoming a shared string passed around between installs.
Only after those checks pass does the website build and sign the entitlement payload.
What the entitlement envelope contains
The signed payload is not a secret. Its strength comes from integrity. The desktop can read the claims, but it cannot forge or modify them without breaking the Ed25519 signature.
- Identity claims: issuer, audience, license ID, user ID, tier, and version
- Binding claims: machine ID, period start, period end, issued-at time, and unique jti
- Expiry claim: entitlement_expires_at, currently issued as a short-lived 48-hour window
The signed payload includes the issuer and audience so the desktop knows who created the entitlement and who it was meant for. It includes the license ID, user ID, tier, machine ID, billing or license period boundaries, issued-at timestamp, unique jti, and payload version.
It also includes entitlement_expires_at. In the current implementation, this is a short-lived 48-hour window from signing time. The desktop refreshes entitlement state on a regular cycle instead of relying on a long-lived token that remains useful for an entire billing period.
The envelope also includes a key ID, the algorithm name Ed25519, the payload, and the base64url-encoded signature. The desktop public-key verifier uses the key ID to select a trusted public key and verify the signature over canonical JSON.
| Claim | Purpose |
|---|---|
| iss / aud | Confirms the entitlement came from the expected issuer and is meant for the desktop |
| license_id / user_id / tier | Identifies the commercial account and enabled plan tier |
| machine_id | Binds the entitlement to the current machine |
| period_start / period_end | Carries the commercial billing or license window |
| entitlement_expires_at | Limits how long the signed entitlement can be trusted locally |
| jti | Gives each signed envelope a unique identifier |
| signature | Proves the payload was signed by KeyRing and was not modified |
How the desktop verifies trust locally
The desktop does not just store the server response. It verifies the Ed25519 signature and then checks the semantic claims that matter for local enforcement.
- Reject if the algorithm is not Ed25519, the key ID is unknown, or the signature is invalid
- Reject if issuer or audience does not match the configured trust anchors
- Reject if machine ID is missing, mismatched, or the entitlement is expired
On the desktop side, KeyRing loads the trusted entitlement public keys from configuration injected at startup. When an entitlement is present, the verifier canonicalizes the payload, verifies the Ed25519 signature, and then checks the claims.
Signature verification is only the first gate. A valid signature over the wrong audience is still rejected. A valid signature for a different machine is rejected. A valid signature that has expired is rejected. The local gate is deliberately specific because the desktop is the enforcement point for provider calls.
That enforcement matters because KeyRing is local-first. The app is not relaying prompts through a KeyRing server that could enforce every request centrally. The desktop runtime needs a local authorization artifact it can verify without putting KeyRing in the user's AI data path.
Why Ed25519 fits this job
Ed25519 gives KeyRing compact signatures, fast verification, and simple public-key distribution. The website keeps the private key; the desktop only needs trusted public keys.
- The private signing key stays server-side
- The desktop can verify entitlements with public keys only
- Key IDs allow key rotation without changing the envelope shape
Ed25519 is a strong fit for this kind of entitlement because the trust direction is one-way. The website signs. The desktop verifies. The desktop does not need the private key and should never have it.
That also makes key rotation practical. The envelope includes a key ID. The desktop has a trusted public-key map. When KeyRing rotates signing keys, the validation service can sign with a new key ID and the desktop can verify against the corresponding public key once that key is trusted in the runtime configuration.
The important product outcome is simple: a user cannot edit their local entitlement from Basic to Pro, swap the machine ID, or extend the expiry without invalidating the signature.
Ed25519 does not replace server-side license validation. It packages the result of that validation into something the desktop can verify locally.
What happens when trust cannot be proven
The production posture is fail-closed for provider-call enforcement. If a signed entitlement is missing, expired, mismatched, or unverifiable, protected provider workflows are blocked instead of silently continuing.
- Validation failures return specific denial states rather than unsigned success
- Desktop enforcement checks entitlement state before protected provider calls
- Development and warning modes exist for local testing, but production enforcement is designed to require a valid entitlement
The point of a signed entitlement is not just to make the happy path cleaner. It also makes failure behavior explicit. If the signature fails, the key ID is unknown, issuer or audience is wrong, the machine binding does not match, or the entitlement has expired, the verifier returns a structured failure reason.
The desktop enforcement layer uses that state before protected provider calls. In production enforcement mode, the application requires a currently valid signed entitlement for those workflows. That keeps local-first architecture from becoming local-only trust.
This is the balance KeyRing is aiming for: the website handles commercial trust, the desktop handles user workflow, and AI traffic still goes directly from the user's machine to the provider.
Frequently Asked Questions
Does KeyRing send prompts or AI responses during license validation?▾
No. License validation is a commercial trust flow. It uses the license key and machine ID. Prompt content, provider API keys, conversation history, generated files, and AI responses are not part of this request path.
Can a user copy the entitlement to another machine?▾
Not usefully. The entitlement includes a machine_id claim, and the desktop verifies that claim against the local machine identity. A copied entitlement for another machine fails the machine-binding check.
Does Ed25519 replace the license database?▾
No. The database remains the source of truth for license status, subscription state, expiry, and machine binding. Ed25519 signs the result so the desktop can verify that result locally.
Why not issue a long-lived entitlement for the whole billing period?▾
A short-lived entitlement is easier to revoke and refresh. The current implementation issues a 48-hour entitlement window and refreshes entitlement state regularly instead of giving the desktop a long-lived trust artifact.
- KeyRing validates licenses server-side, then signs the result as an Ed25519 entitlement envelope.
- The desktop verifies signature, issuer, audience, machine ID, and expiry before trusting the entitlement.
- This keeps commercial trust on the website while keeping prompts, provider keys, and AI responses out of KeyRing's server path.
Related Reading
What Most AI Desktop Apps Get Wrong About Privacy
Privacy is not just about whether an AI app is installed locally. It is about the real data path: where the backend binds, where keys live, where chat history is stored, which servers still get contacted, and whether prompts are relayed through someone else's infrastructure.
Local-First AI Apps vs Cloud Relays: What Actually Matters
The important difference is not desktop versus web. It is whether prompts, keys, and state stay in a local runtime or pass through a cloud relay.
How Your API Keys Stay Private
KeyRing AI stores provider credentials locally and decrypts them only for outbound provider requests. Here is what that means in practice.