@oshon-ai/license-core
v0.9.1
Published
Offline Ed25519 license verification for Oshon commercial packages. Zero phone-home, embedded public key, grace + lapse semantics built in.
Downloads
254
Maintainers
Readme
@oshon-ai/license-core
Offline Ed25519 license verification for Oshon's commercial packages. Zero phone-home, embedded public key, grace + lapse semantics built in.
The library itself is MIT. The licenses it validates are commercial — see LICENSE-COMMERCIAL.md at the repo root.
Why it exists
Every Oshon Pro package (@oshon-ai/data, governance, patterns,
brand-forge, cli-pro, mcp-server-pro) needs to verify a paying
customer's license at boot. We do that with a signed JWT (Ed25519)
that ships on the customer's machine — no network calls to
verify, no analytics, no phone-home.
The signing private key lives in the Oshon issuer service. The verifying public key is baked into this package. Together they form a one-way cryptographic boundary: customers can read what's in their license, but they can't forge a new one or extend an expired one.
Install
pnpm add @oshon-ai/license-coreUsage
import { verifyLicense, loadLicense } from '@oshon-ai/license-core';
// Resolve the license JWT from $OSHON_LICENSE / ~/.oshon/license / etc.
const jwt = await loadLicense();
if (!jwt) {
throw new Error('No Oshon license found. Run `oshon login`.');
}
const result = await verifyLicense(jwt, {
expectedMajorVersion: 'v1',
});
switch (result.status) {
case 'valid':
// Full functionality. If `gracePeriodEndsAt` is non-null,
// the license is past its `period_end` but inside grace —
// tell the customer to renew.
break;
case 'lapsed':
// The paid period elapsed and grace ran out. The customer
// KEEPS perpetual use of the version they already installed
// (see `LICENSE-COMMERCIAL.md` §4(e)) — but refuse to
// download / install / upgrade to a newer version.
console.warn(`License lapsed on ${result.lapsedAt.toISOString()}`);
break;
case 'invalid':
// Bad signature, malformed JWT, or audience mismatch (e.g.
// a v1 license being used to run a v2 package). Refuse to load.
throw new Error(`Invalid Oshon license: ${result.reason}`);
}Three-state result
| Status | Meaning | What the package should do |
| ---------- | ------------------------------------------------------------------ | ----------------------------------- |
| valid | Active subscription, signature OK, audience matches | Run normally, allow updates |
| lapsed | Subscription canceled or paid period + grace expired | Keep installed version, block updates |
| invalid | Signature failed, malformed, wrong issuer, or audience mismatch | Refuse to load |
Lapse semantics
Oshon's commercial license includes a perpetuity clause: when a customer's subscription lapses, they keep the right to use the specific version they already installed — forever. They just don't get any new versions, security patches, or support.
This package implements that by returning status: 'lapsed' instead
of status: 'invalid' when the paid period has elapsed. The
consuming Pro package keeps running fine; the cli-pro upgrade
command and the postinstall hook in commercial packages check the
status and refuse to advance the installed version.
Audience checks (major version)
Each license is issued for one or more major versions — encoded
in the JWT's standard aud claim. A v1 license has aud: ['v1']
and is rejected when running v2 packages with expectedMajorVersion:
'v2'.
This is how LICENSE-COMMERCIAL.md §3 enforces "v2 / v3 require new
license purchases" — the runtime simply refuses to load.
Resolution sources (in order)
loadLicense() tries these in order; first non-empty wins:
opts.jwt— explicit string from the calleropts.customResolver()— for Bun, Deno, edge runtimesprocess.env.OSHON_LICENSE(override the env var name viaopts.envVarName)opts.filePath— explicit path~/.oshon/license— user-scope canonical location./.oshon/license— project-scope canonical location
Returns null if nothing was found. Verification is the consumer's
call (fail-closed, or fall through to a free tier).
Security model
- Embedded public key. Tampering with the bundled key in this
package will cause
verifyLicenseto reject every legitimate license — there's no fallback or alternate key. - Strict algorithm pinning. Only
EdDSAis accepted. An attacker can't downgrade to a weaker JWS algorithm by editing the JWT header. - Strict issuer pinning. Only
oshon.aiis accepted asiss. - Clock-skew tolerance. Defaults to 60 seconds; tunable via
clockSkewSeconds. - Grace window. Defaults to 7 days past
period_endbefore the license flips tolapsed; tunable viagracePeriodDays. Buys time for renewal payments to settle.
License (the validator)
MIT. See LICENSE.
