title: Offline JWT licence & daily‑run quota description: How Stella‑Ops enforces a runs‑per‑day limit in fully air‑gapped deployments. nav: order: 36

JWT‑based daily‑run licence (offline‑capable)

When Stella‑Ops scanners operate entirely offline, they cannot phone home for metering.
Instead, the backend accepts a signed JSON Web Token (JWT) that states the maximum number of scans per UTC day.
If no token is supplied, a grace quota of 33 runs/24 h applies.


1 Token contents

Claim Purpose Example
sub Customer / licensee identifier "f47ac10b…"
iat Issued‑at timestamp 1722566400
exp Absolute licence expiry 2025‑12‑31T23:59:59Z
tier Max scans per UTC day {{ quota_token }}
tid Token identifier (32‑byte) "7d2285..."
pkg Product SKU / edition "stella‑core"

Tokens are signed with RS256 and verified locally using the bundled public key. Only the public key ships inside the container; the private key never leaves the build pipeline.


2 Obtaining a token

  1. RequestPOST /​register { email:"alice@example.org" }
  2. Service hashes the e‑mail (SHA‑256), stores it, and issues a JWT (60 days by default).
  3. Token is e‑mailed to you.

A new request for the same e‑mail returns the same token until it nears expiry, avoiding quota “top‑ups” by re‑registration.


3 Supplying the token to an air‑gapped stack

# recommended
docker run \
  -v /opt/stella/license/alice.jwt:/run/secrets/stella_license.jwt:ro \
  stella‑ops

Other supported paths:

Method Mount point Hot‑reload
Docker secret /run/secrets/… ✓ (inotify)
Bind‑mounted user‑chosen path (above)
Env variable STELLA_LICENSE_JWT ✗ restart

4 Quota‑enforcement algorithm

flowchart TD
    Start --> Verify[Verify JWT signature]
    Verify -->|Invalid| Deny1[Run in non licensed mode]
    Verify --> Load[load today's counter UTC]
    Load -->|SUM of last 24h scans < daily_quota| Permit[allow scan, add scan]
    Permit --> End
    Load -->|SUM of last 24h scans ≥ daily_quota| Deny1

5 Renewal procedure

Scenario Action
More capacity Request new token with higher daily_quota; replace file – no restart needed
Licence expiry Same as above; new exp date
Key rotation Container image ships new public key(s); older tokens still verify

6 Fallback limits

Situation Daily quota
Valid JWT present value of daily_quota claim (333)
No JWT 33
JWT expired (if used) treated as anonymous unless policy enforces hard‑fail
Token signature invalid 0 (reject)

7 Threat‑model highlights (future work / optional hardening)

Threat Mitigation
Copy token & DB to 2nd node Bind sub/tid to host fingerprint (TPM EK) – optional enterprise control
Counter DB rollback Hash‑chain + monotonic clock – optional enterprise control
Flooding single node Redis‑backed cluster rate‑limit (30 hits / 60 s) + edge Nginx (20 r/s)
Key compromise Rotate RS256 key‑pair, ship new pubkey, re‑sign tokens

8 Anonymous (33 runs) mode

Offline PoCs without registration still work:

docker compose exec stella-ops stella-jwt reload   # reloads, discovers no token

…but production deployments must register to unlock real‑world quotas and receive security advisories via e‑mail.


Last updated: 2025‑08‑02