Skip to content

License API

Signed document contract

The existing Ed25519 JWS envelope is used:

{"format":"magicstick-license/v1","token":"<Ed25519 compact JWS>"}

The header contains only alg: EdDSA, typ: magicstick-license+jwt and a trusted kid. Keys embedded or linked in uploads are never trusted.

Signed field Contract
version Integer 1
product, issuer Both magicstick
edition free-registered or commercial
licenseId Unique bounded identifier
customer Nonempty customer/organization reference, at most 160 characters
issuedAt, notBefore, expiresAt Integer Unix seconds; issuedAt <= notBefore < expiresAt
features Unique entitlement ID list matching the edition above
installationId Optional canonical UUID binding

The wire field features represents entitlements; no separate boolean map is needed. Unknown/duplicate fields and entitlement IDs fail closed. Future entitlements are added centrally to the verifier, contracts and edition policy with tests, not implicitly trusted from unknown signed claims. For example:

{
  "version": 1,
  "product": "magicstick",
  "issuer": "magicstick",
  "edition": "free-registered",
  "licenseId": "example-registration",
  "customer": "Example organization",
  "issuedAt": 1798761600,
  "notBefore": 1798761600,
  "expiresAt": 1830297600,
  "features": ["federated-sso"]
}

Commercial claims use edition: commercial and both entitlement IDs. The issuer can omit installationId for an unbound file. The browser request includes it. Files are limited to 64 KiB. Invalid, expired, future-dated or incorrectly bound uploads cannot replace the current license. Activation uses Kubernetes resourceVersion for optimistic concurrency; there is one active file, no scheduled replacement, billing system, online activation or grace period.

Persistence, API and security

The runtime Secret identity-system/magicstick-license contains a random installationId and, after activation, license.json. It is not Git-owned. Back up the Secret through secured cluster backup; exporting only the document does not preserve the binding identity. Secret data is base64, not encryption; cluster encryption at rest is an installation responsibility.

API Purpose
GET /api/license Sanitized status, edition, validity, installation ID, revision, capabilities
POST /api/license/request Customer, edition, features, ttlSeconds → unsigned private request
POST /api/license/validate Preview signed document against current installation
PUT /api/license Activate document using expectedRevision
GET /api/license/export Export exact stored document

All routes require administrator authorization; mutations also require the dashboard CSRF boundary. License payloads and secrets must not appear in audit logs. CLI: magicstick license status, validate FILE, import FILE --yes, export FILE; the TUI provides preview and explicit activation.

LicenseService.require_capability combines live caller authorization, cryptographic entitlement and installed implementation. Federated SSO uses this gate. Resource Sharing instead checks live local users, groups, roles and ACLs; Mesh checks tokens, membership, signed rosters, invitations and role isolation. A license never replaces these security checks.

Invalid or expired licenses grant neither entitlement. Core workloads, ACLs and mesh policies remain intact. A local root/cluster administrator can alter code, clock or trust stores; offline signature verification is not tamper-proof DRM.

License Administration

The dashboard System → License tab and the CLI/TUI License area use five admin-only routes: GET /api/license, POST /api/license/request, POST /api/license/validate, PUT /api/license, and GET /api/license/export. Mutations require the existing CSRF/same-origin checks. Preview does not replace the license; activation revalidates the signed file and the preview's expected Kubernetes revision. Invalid files cannot overwrite a valid license. A valid entitlement does not make an unimplemented feature available.

The Request license panel selects Free Registered or Commercial, a customer reference and positive whole TTL in hours or days (initial draft: 30 days). It downloads unsigned claims for the offline issuer, including the edition, edition-specific entitlements and installation binding. Download never activates a license. The entitlements are federated-sso and commercial-production.

Software licenses remains visible when the API is unavailable and embeds LICENSE, LICENSING.md, licenses/MIT-CHANGE.txt and THIRD_PARTY_NOTICES.md for offline inspection/download. A signed license is technical activation, not a substitute for a commercial agreement. See the licensing overview.

The API image adds pinned verification libraries and combines the release-owned magicstick-license-official-trust with the optional local magicstick-license-trust ConfigMap. Both are read-only mounts; official keys arrive with installation/updates, including when the preserved local store is empty. Customers upload only their signed license file. Conflicting key IDs fail closed, and retired official IDs cannot be restored by a local copy. Its separate Role grants get/update on the named identity-system/magicstick-license Secret plus namespace-scoped Secret creation (Kubernetes cannot restrict create by name). It cannot list or delete identity Secrets, edit trust keys or install workloads. The runtime license Secret is not Git-owned and survives API Pod replacement.

See licensing.md for the complete contract, issuer commands, key rotation, backup, expiry, tamper-resistance limits and local Rancher tests. All core functions except Federated SSO remain usable without a license file.