CLI tool for generating Ed25519-signed software licenses.
Part of the license-guard ecosystem.
cargo install license-forge1. Create a product → generates Ed25519 keypair
2. Embed the public key → in your app (via license-guard)
3. Issue licenses → signs a payload with the private key
4. Distribute .lic files → to your users
5. App validates offline → using the embedded public key
# 1. Create a product (generates keypair + config)
license-forge product add my-app
# 2. Copy the public key for embedding
license-forge show
# Public key (for embedding):
# e8601e48b69383ba520245fd07971e983d06d22c4257cfd82304601479cee788
# 3. Issue a license to a user
license-forge license add --sub "[email protected]" --ent "premium,export"
# 4. Verify it works
license-forge verify alice_at_example_com.licA license is a JSON file containing a base64-encoded payload and its Ed25519 signature. The payload has these fields:
| Field | Type | Description |
|---|---|---|
v |
u32 |
Schema version (currently 1) |
sub |
string |
Licensee — email, user ID, or company name |
iss |
string |
Issuer — product identifier (from product.toml) |
iat |
u64 |
Issued at — Unix timestamp (UTC) |
exp |
u64? |
Expires — Unix timestamp (UTC), omitted for perpetual |
ent |
[string] |
Entitlements — feature flags (e.g. ["premium", "f5"]) |
meta |
{k: v} |
Metadata — arbitrary key-value pairs |
{
"payload": "eyJ2IjoxLCJzdWIiOiJhbGljZUBleGFtcGxlLmNvbSIsImlzcyI6...==",
"sig": "MEUCIQD7x8z3y4z5..."
}The payload is the base64-encoded JSON of the fields above. The signature is the Ed25519 signature over the raw JSON bytes (not the base64).
Create a new product with an Ed25519 keypair.
license-forge product add my-appPrompts interactively for:
- Product identifier — appears as
issin licenses - Entitlements — predefined list users can pick from when issuing licenses
Creates ~/.config/license-forge/my-app/ with product.toml, license.private, and license.pub.
List all products with their key status and license count.
Remove a product and all its licenses. Prompts for confirmation.
Generate a new signed license. Runs interactively by default, or accepts all parameters via CLI flags for scripting:
| Flag | Description | Example |
|---|---|---|
--sub |
Licensee email/identifier | --sub "[email protected]" |
--exp |
Expiration date (YYYY-MM-DD) | --exp 2026-12-31 |
--ent |
Comma-separated entitlements | --ent "premium,export" |
--meta |
Comma-separated key=value pairs | --meta "seats=5,org=Acme" |
Interactive mode (prompts for each field):
license-forge license addScripted mode (no prompts when all flags are provided):
license-forge license add \
--sub "[email protected]" \
--exp 2026-12-31 \
--ent "premium,export" \
--meta "seats=5,org=Acme Inc"Perpetual license (omit --exp):
license-forge license add --sub "[email protected]" --ent "premium"Saves to ~/.config/license-forge/<product>/licenses/<sub>.lic.
List all licenses for a product with status (active, expired, perpetual).
Immediately expire a license (sets exp to now, re-signs). Creates a
backup .bak file first.
Extend a license's expiration date. Prompts for a new date. Creates a backup first.
Verify a license file against the product's public key.
license-forge verify alice_at_example_com.licShows: validity, licensee, issuer, dates, entitlements, and metadata.
Exits with code 1 if invalid.
Display product details, public key (for embedding), and license count.
Generate shell completions (bash, zsh, fish).
license-forge completions bash >> ~/.bashrc
license-forge completions zsh >> ~/.zshrc
license-forge completions fish > ~/.config/fish/completions/license-forge.fishUse -p to target a specific product (default: default):
license-forge -p my-app license add --sub "[email protected]"
license-forge -p my-app show
license-forge -p my-app license listEach product is stored in ~/.config/license-forge/<name>/:
~/.config/license-forge/
├── default/
│ ├── product.toml # Product configuration
│ ├── license.private # Ed25519 private key (KEEP SECRET)
│ ├── license.pub # Ed25519 public key (embed in your app)
│ └── licenses/
│ ├── alice_at_example_com.lic
│ └── bob_at_corp_com.lic
└── my-app/
└── ...
name = "my-app"
entitlements = ["premium", "export", "f5"]| Field | Description |
|---|---|
name |
Product identifier — appears as iss in every license |
entitlements |
Predefined entitlement names — shown as a pick-list during license add |
license.private— hex-encoded 32-byte Ed25519 signing key. Keep this secret. If compromised, anyone can forge licenses.license.pub— hex-encoded 32-byte Ed25519 verifying key. Embed this in your application source code.
In your Rust application, add license-guard and embed the public key:
use license_guard::global;
// Public key from: license-forge show
global::init("e8601e48b69383ba520245fd07971e983d06d22c4257cfd82304601479cee788")?;
// Load + activate a license the user provides
let license = license_guard::LicenseFile::from_path("license.lic")?;
let data = serde_json::to_string(&license)?;
global::activate(&data)?;
// Check entitlements anywhere
if global::has("premium") {
// premium feature
}See the license-guard docs for the full API.
MIT OR Apache-2.0