Online Activation
Online activation is an optional convenience for internet-connected
deployments. Instead of distributing an offline .license file, your own code
(or the Bitruvius SDK) trades an API key for a short-lived, signed lease and
writes it to disk. The codec then validates that lease file locally, exactly like
any other license.
Crucially, the codec never touches the network. It embeds no HTTP client and makes no activation calls and no per-image calls. Fetching the lease is something your application code, or the SDK, does out-of-band — the codec only ever reads and verifies a file on disk.
It runs alongside the offline signed-file path — it does not replace it. If
you operate air-gapped, keep using offline .license files; see Air-gapped deployment. A valid offline file always
takes precedence over a lease.
Who does what
| Step | Who | Network? |
|---|---|---|
| Hold the API key and call the activation service | your code / the SDK | yes — once per lease window |
Write the returned lease into ~/.bitruvius/ | your code / the SDK | no |
| Read the lease file and verify it on every encode | the codec | never |
The codec is byte-for-byte the same as the air-gapped build: it validates a
signed file on disk. Whether that file is an offline .license you copied in or a
lease your code fetched makes no difference to the codec, and no difference to the
encode hot path.
No per-image network calls
Activation is not a per-operation license check. Your code (or the SDK)
fetches a lease at most once per lease window; the codec then verifies the
file offline on every call, exactly like an offline .license file. There is
no DNS, HTTPS, or telemetry on the encode/decode hot path — and no network code
inside the codec at all.
- One activation request per lease window — never per image.
- The lease is verified locally by the codec; the network is never on the encode path.
- The codec embeds no HTTP client; only your code or the SDK reaches the activation service.
- Decoders are unlicensed and make no network calls of any kind.
The lease vs. offline trade-off
Offline .license file | Online lease | |
|---|---|---|
| Runtime network (codec) | none, ever | none, ever |
| Lease acquisition | you copy the file in | your code / the SDK fetches it, once per window |
| Validity | long-lived, uncapped | short-lived, capped at 30 days |
| Best for | air-gapped / SCIF / DoD | CI runners, autoscaling fleets, dev laptops |
Online leases are deliberately a separate, lower-trust class than offline files. The verifier hard-caps any lease at 30 days and rejects never-expiring leases, so a lease can never become a long-lived entitlement.
API keys
Create and manage keys in the portal at API keys (org admins
only). A key looks like btr_live_<keyid>_<secret>.
- The secret is shown once. Store it in your secret manager immediately; it cannot be retrieved again. Rotate or revoke from the same page.
- A key is scoped to one or more product or suite ids. A suite scope (e.g.
3d-suite) automatically expands to the suite’s current members. - The scope picker only offers entitlements provisioned for online activation. Entitlements your org receives as a signed offline license file are delivered that way instead, and don’t appear here — there’s nothing for an online key to activate. Your dashboard tags each entitlement with its delivery method.
- We store only a peppered hash of the secret — never the secret itself.
Treat the key like any other production credential: one per environment, least scope, rotate on a schedule. The key lives in your application/SDK environment, not in the codec — the codec never sees it.
Locking down API keys
When you create a key you can attach up to three optional, opt-in restrictions. Leave them blank and the key is unrestricted — exactly the default behavior. Set them from the Restrictions (optional) panel of the create-key dialog at API keys (org admins; staff can also view and set them from your org’s admin page).
All three are enforced only at the activation endpoint — at the moment a key
is exchanged for a lease (POST https://activation.bitruvius.com/activate), after the key’s signature and status are checked and before a lease is
minted. They are never evaluated per image. Once a lease is issued the codec
validates it offline as usual, so restrictions add zero runtime cost to
the encode path. A violation returns HTTP 403 with a clear message and no
lease.
Allowed IPs / CIDRs — a real network boundary
Provide one or more CIDR ranges (IPv4 or IPv6; a bare address is treated as a /32 or /128). The key will only mint a lease when the caller’s IP falls
inside one of the allowed ranges. The client IP is the edge-observed peer
address (resolved from CloudFront-Viewer-Address, falling back to X-Forwarded-For), not a client-supplied value, so this is a genuine
boundary. Ideal for server-side integrations with known egress IPs (CI
runners behind a NAT, a fixed render-farm range). A caller outside every allowed
range is rejected with “API key is not permitted from this network address”.
Allowed origins — browser / WASM only
List the exact browser origins permitted to use the key, e.g. https://app.example.com. This is intended for browser / WASM integrations:
the activation API enforces the Origin header and speaks CORS (it echoes
allowlisted origins back in Access-Control-Allow-Origin and answers the
preflight), so a real browser on a disallowed origin is blocked before the
request even reaches your key.
Be aware that Origin is a client-settable header. It is therefore advisory for non-browser / server-side clients — a custom HTTP client can
send any Origin it likes, so an origin allowlist is not a security boundary
against server callers (use the IP allowlist for that). An origin-restricted key
is effectively browser-only: a request that arrives with no Origin, or
a disallowed one, is rejected with “API key is not permitted from this
origin”. Do not set an origin restriction on a key your server code uses — its
requests carry no Origin and will be refused.
Max machines — a seat / device cap
Cap the number of distinct device fingerprints that may activate the key. Once that many distinct devices have activated, a new device is rejected with “device limit reached for this API key”, while already-seen devices keep re-activating freely (refreshing their leases is never blocked). This is a seat limit layered on top of the lease’s existing per-machine fingerprint binding and short TTL — it bounds how many machines a single key can spread to.
Fetching a lease
The Bitruvius SDK ships an ActivationClient (the activation feature of the bitruvius-license crate) that your build links — the codecs themselves do
not. It accepts the key programmatically or reads it from the environment:
| Var | Purpose |
|---|---|
BITRUVIUS_API_KEY | Your btr_live_… key. |
BITRUVIUS_ACTIVATION_ENDPOINT | The activation service URL (e.g. https://activation.bitruvius.com/activate). |
// In YOUR application code (or the SDK) — never inside the codec:
let client = ActivationClient::from_env()?; // reads BITRUVIUS_API_KEY + endpoint
// or pass them in directly:
// let client = ActivationClient::new(api_key, endpoint);
client.ensure_fresh(product, fingerprint)?; // one POST per window → ~/.bitruvius/lease.license ensure_fresh writes the lease to ~/.bitruvius/lease.license and refreshes it
out-of-band at the midpoint of the lease window, so a transient network blip
never interrupts encoding. The codec, running separately, simply reads that file
and validates it offline on every call.
Prefer not to take the SDK dependency? Call POST $BITRUVIUS_ACTIVATION_ENDPOINT yourself with Authorization: Bearer $BITRUVIUS_API_KEY, write the returned lease
into ~/.bitruvius/, and skip the client entirely. The codec only cares that a
valid lease file is on disk.
Revocation SLA
Refreshing a lease is gated by the key’s and contract’s status, so revoking a
key (or letting it expire) stops the next refresh. Active leases keep working
until they expire; the maximum exposure after revocation is one TTL (default
~7 days, capped at 30). For an immediate cutoff, set a short lease_ttl_secs when you create the key.
Usage visibility
Activation calls let us report adoption and seat counts to your account team. These metrics are computed only on our backend from the activation requests — never on your machines, neither in the SDK nor in the codec. Air-gapped customers, who never activate online, are reported from license issuance instead.