Files
yama-issue-token/README.md
yuanyuanxiang 6a4321c4cd docs(readme): point all repo URLs at Gitea (authoritative host)
GitHub mirror is no longer maintained; git.simpleremoter.com is the live
host for both SimpleRemoter and yama-issue-token. Update source-code
link, both clone commands, and the licensing-package tree link.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 22:14:05 +02:00

4.1 KiB

yama-issue-token

CLI to mint customer JWTs (RS256) for the YAMA Go server's License Server (/license/sign, /license/heartbeat).

A thin shell around licensing.Issue() in the YAMA Go server — all validation (tier rules, TTL floor, sub required) lives there, so this tool stays in sync as the licensing package evolves.

Status

Personal hobby project, MIT license. Not a commercial product, no SLA.

Build

This module uses a local replace directive to consume the YAMA licensing package from a sibling checkout — go install from a fresh clone will fail. Build it locally:

git clone https://git.simpleremoter.com/yuanyuanxiang/SimpleRemoter.git ../SimpleRemoter
# yama-issue-token expects YAMA at ../YAMA/server/go (see go.mod replace);
# if you cloned as SimpleRemoter, either rename or adjust the replace line.

git clone https://git.simpleremoter.com/yuanyuanxiang/yama-issue-token.git
cd yama-issue-token
go build -o yama-issue-token .

go.mod currently pins:

replace github.com/yuanyuanxiang/SimpleRemoter/server/go => ../YAMA/server/go

This is kept on purpose during local development — the tool tracks the in-tree licensing package. A pinned-version setup may come later.

One-time RSA keypair

The License Server verifies issued JWTs with the public key. Generate once, keep the private key on the issuer machine only:

openssl genrsa -out license_priv.pem 2048
openssl rsa  -in  license_priv.pem -pubout -out license_pub.pem

Hand license_pub.pem to the License Server (YAMA_LICENSE_PUBLIC_KEY). The private key stays with whoever is issuing tokens.

Usage

yama-issue-token -priv <license_priv.pem> -sub <customer-id> [options]

Required:
  -priv  RSA private key PEM (PKCS#1 or PKCS#8).
  -sub   Customer ID — unique string; lands in the JWT "sub" claim.

Options:
  -tier  trial | paid                       (default: trial)
  -max   Max concurrent devices             (trial default: 20;
                                             paid: REQUIRED, no default)
  -days  Token TTL in days                  (default: 365; minimum: 1 hour)
  -out   Write token to this file (0600)    instead of stdout

The signed JWT goes to stdout (single line, no trailing whitespace). Issuance details (sub / tier / max / expires) go to stderr and remain visible when stdout is redirected.

Examples

# Trial customer, 5 devices, 30 days, print to terminal
yama-issue-token -priv license_priv.pem -sub acme-trial -tier trial -max 5 -days 30

# Paid customer, 200 devices, 1 year, write to file (mode 0600)
yama-issue-token -priv license_priv.pem -sub acme-corp -tier paid -max 200 -out token-acme.jwt

# Pipe into env var (Linux/macOS shell)
export YAMA_LICENSE_TOKEN=$(yama-issue-token -priv license_priv.pem -sub acme -tier paid -max 100)

Tier semantics

Tier -max default Notes
trial 20 Inherits the C++ anti-proxy RTT logic on server
paid required No default — must be supplied explicitly

Integration

Set on the customer's Go server (RemoteSigner mode):

YAMA_LICENSE_SERVER=https://license.example.com
YAMA_LICENSE_TOKEN=<the JWT this tool produced>

The customer's server never sees the master HMAC key — it HTTPS-POSTs to /license/sign for each new device login, then caches the signature for 24h (YAMA_LICENSE_OFFLINE_HRS).

See the YAMA repo for the License Server side: server/go/licensing/.

Security

  • Private key has no business leaving the issuer host. .gitignore excludes *.pem, *.key, *.jwt, token-*.jwt, license_priv*, license_pub*.
  • -out writes with mode 0600.
  • JWT alg is locked to RS256 server-side — alg:none attacks are rejected.

License

MIT