License key
The framework is fully usable without a license. Every concept in the documentation — connectors, dictionary, screens, menus, dashboards, charts, jobs, auth — works on the open feature set on a fresh install.
A license key unlocks a curated set of additional integrations: a few production-grade connectors (proprietary databases, custom APIs), packaged customer apps and advanced features. The key is set under Settings → Framework → License and its live status is surfaced on the dedicated Settings → License page.
At a glance
Settings → License
The dedicated License tab is read-only and surfaces the current state.
| Field | Source |
|---|---|
| Status | Accepted / Rejected — <reason> / Not configured. |
| Customer | The customer claim of the JWT. |
| Edition | The edition claim. |
| Expires | The exp claim. A warning chip appears 30 days before expiry. |
| Licensed connectors | List from the key's features.connectors. A red dot appears next to entries that aren't actually defined in the install. |
| Licensed apps | Same shape for features.apps. |
| User cap | Current user count + cap, with a 90% / 95% / 100% colour scale. |
| AI entitlements | Allowed providers + daily message cap + current usage. |
| ↻ Re-verify | Re-reads the key from the environment and re-verifies the signature without a restart. |
The tab is gated by license:read.
Installing a key
The key lives in the environment of the host (kept out of disk). In Settings → Framework → License, the License key field stores the name of the environment variable holding the JWT, not the JWT itself:
| Field | Effect |
|---|---|
| License key | Reference to the env var. Default ${LIBERTY_LICENSE_KEY}. |
| Public key path | Optional override for the bundled public key. Useful when running with a private signing authority (OEM partners that re-sign keys). |
Installing a new key on a host:
- Export the JWT under the env var:
export LIBERTY_LICENSE_KEY="eyJhbGciOi…". - Restart the framework, or click ↻ Re-verify on the License tab — the framework re-reads the variable and re-runs the signature check without a full restart.
The startup log prints one line of confirmation:
INFO liberty.licensing license accepted — customer="Acme Corp" edition="enterprise" expires=2026-05-19T00:00:00Z
A bad key logs the failure and continues; the framework enters restricted mode:
WARN liberty.licensing license rejected — reason="signature invalid"
WARN liberty.licensing running in restricted mode — licensed features disabled
In restricted mode:
- Every connector marked Licensed is hidden — it doesn't appear in the catalogue, the AI tool list or any menu.
- Packaged apps in the key's
features.appsdon't register their content. - The License tab shows the rejection reason and a banner appears across the header.
- Every other concept (open connectors, screens, menus, dashboards, jobs, auth) keeps working.
Restricted mode is the default on a fresh install with no key — it isn't an error state, it's the unlicensed mode.
What's in a licensed connector
In Settings → Connectors, every entry has a Licensed toggle. When on, the connector loads only when its identifier is present in the key's features.connectors. In restricted mode, the Connectors page lists the connector as Locked — requires license <id> with the rest of its definition greyed out.
This is what gates the bundled vendor connectors (JD Edwards, SAP, Snowflake, …). The mechanism is open — customers can mark their own connectors Licensed and ship keys to their own customers if they distribute custom apps.
Verifying a key out-of-band
The liberty-license CLI verifies a key without booting the framework:
.venv/bin/liberty-license verify "$LIBERTY_LICENSE_KEY"
# license accepted
# customer="Acme Corp" edition="enterprise"
# expires=2026-05-19T00:00:00Z (in 30 days)
# features.connectors: [jdedwards, sap, snowflake]
# features.apps: [nomajde, nomasx-1]
Exits non-zero with the diagnostic on bad / expired / wrong-audience keys. See CLI reference → liberty-license for every flag.
Rotation and renewal
A renewal key is installed by:
- Export the new JWT under the env var on each host.
- Restart the framework, or click ↻ Re-verify.
For high-availability installs:
| Phase | Action |
|---|---|
| 30 days before expiry | Request the renewal key from the vendor. The current key's Expires chip turns yellow. |
| 7 days before expiry | Install the new key on each replica via your secret-management tool. |
| At expiry | Old key naturally rejected; new one takes over. No restart required because the rolling secret update already happened. |
Failure modes
The Settings → License tab surfaces the diagnostic directly. Common rejections:
| Status text | Cause | Recovery |
|---|---|---|
signature invalid | Wrong public key, tampered JWT. | Re-check the key. If using a partner signing authority, set Public key path to its key. |
expired (2026-04-30) | Past exp timestamp. | Install a renewed key. |
audience mismatch | The JWT was issued for a different product. | Confirm the vendor sent a Liberty key. |
malformed | The env var doesn't contain a valid JWT (extra whitespace, accidental truncation). | Re-export the key carefully — copy from the source verbatim. |
user cap reached | The key's features.users.max matches the current user count. | Request a larger cap, or deactivate inactive users. |
Permissions
The License tab is gated by license:read (view) and license:write (re-verify, swap public key path). The Framework → License sub-form is gated by settings:framework.
Tips & best practices
- Treat the key as configuration, not a deep secret. It's signed and verifiable on the receiver side; pasting it into a Slack thread doesn't compromise anything. Keep it in your secret manager anyway for hygiene.
- Set Public key path only when needed. The default works for keys issued by Nomana-IT — overriding is for partner / OEM deployments only.
- Watch the 30-day expiry chip. Renewing late means a short window where licensed connectors disappear from the UI.
- Never edit a key by hand. A single character change invalidates the signature; ask the vendor for a new key instead.
- Keep the open feature set self-sufficient. A well-designed install should still be useful in restricted mode — use licensed connectors for differentiation, not for the core flow.
Under the hood
The license payload is stored only in memory after the env var is read. The Settings → Framework form persists the name of the env var + the optional public-key path; the JWT itself never lands on disk. The settings are stored in config/app.toml under the [license] section.
What's next
- Authentication — JWT for users (different mechanism, same JWT format).
- Roles & permissions —
license:readand the rest of thesettings:*family. - Configuration → Environment variables —
LIBERTY_LICENSE_KEYin the env contract.