Skip to main content
SecurityEd25519License ValidationEntitlementsDesktop ArchitectureLocal-First

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.

May 12, 20264 min readBy KeyRing AI Team
AuthorKeyRing AI Team
PublishedMay 12, 2026
Verified onKeyRing AI desktop - Windows release
TL;DR

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.

Key Takeaways
  • 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.

ClaimPurpose
iss / audConfirms the entitlement came from the expected issuer and is meant for the desktop
license_id / user_id / tierIdentifies the commercial account and enabled plan tier
machine_idBinds the entitlement to the current machine
period_start / period_endCarries the commercial billing or license window
entitlement_expires_atLimits how long the signed entitlement can be trusted locally
jtiGives each signed envelope a unique identifier
signatureProves 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.

Insight

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.

In 60 Seconds
  • 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