> For the complete documentation index, see [llms.txt](https://docs.telys.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.telys.ai/licensing/offline-licenses.md).

# Offline licenses

Your Telys license is a **signed JSON Web Token (JWT)**, not a database row looked up over the network. It carries your tier and features, signed by the license authority. The runtime verifies the signature locally with an embedded public key, so licensing works offline.

## What the license is

[`telys login`](/licensing/device-code-sign-in.md) downloads a license and caches it at `$TELYS_HOME/login_license.jwt` (default `~/.telys/login_license.jwt`). The signed runtime carries its own license at `~/.telys/runtime/<platform>/license.jwt`. Both are offline JWTs.

Verification checks these claims:

| Claim            | Value                               | Meaning                                                  |
| ---------------- | ----------------------------------- | -------------------------------------------------------- |
| `iss` (issuer)   | `https://license.algenta.ai`        | Who signed the license                                   |
| `aud` (audience) | `telys-runtime` / `algenta-runtime` | Which runtimes may accept it                             |
| `ver`            | `2`                                 | The supported license schema version                     |
| `products.telys` | `{ tier, features }`                | Your Telys tier and the features it unlocks              |
| `exp` + grace    | timestamp + window                  | When it expires, plus a grace period before hard failure |

{% hint style="info" %}
The **grace window** keeps a dropped connection or a just-expired license from locking you out mid-session. Verification honors `exp` plus the grace period, giving you time to refresh (for example, `telys login`).
{% endhint %}

## How it is verified

Verification is strict, offline, and asymmetric. Telys embeds the authority's **public** key in the wheel (`telys/_keys/telys_license_pub.pem`); only the authority holds the private key, so a license cannot be forged or altered without breaking the signature. The check:

1. Pins the algorithm to **RS256** (RSA + SHA-256) and rejects any `crit` header; a different or downgraded algorithm is refused.
2. Confirms the signature against the embedded (or overridden) public key.
3. Checks `iss`, `aud`, and `ver == 2`.
4. Checks `exp` plus the grace window.
5. Reads `products.telys` for your `tier` and `features`.

No step contacts a server. The `cryptography` dependency performs the signature math locally.

## Verify a license yourself

The verification API is in `telys.verify`. To check a token you hold — for example, the one cached by login — read it and call `verify_license` with the current time:

```python
import time
from pathlib import Path

from telys.verify import verify_license

token = Path.home().joinpath(".telys", "login_license.jwt").read_text().strip()

claims = verify_license(token, now=int(time.time()))
print(claims["products"]["telys"]["tier"])       # e.g. "telys_pro"
print(claims["products"]["telys"]["features"])    # unlocked features
```

`verify_license(token, pubkey=None, *, now, issuer=None, audience=None, product="telys")` returns the decoded claims, or raises on any failure (bad signature, wrong issuer or audience, unsupported version, or an expiry past the grace window). Passing `now` explicitly keeps verification deterministic.

The module also exposes its enforced defaults and the keys it uses:

```python
from telys import verify

print(verify.DEFAULT_LICENSE_ISSUER)      # https://license.algenta.ai
print(verify.DEFAULT_LICENSE_AUDIENCES)   # ("telys-runtime", "algenta-runtime")
print(verify.SUPPORTED_LICENSE_VER)       # 2
print(verify.PRODUCT)                      # telys
print(verify.license_public_key())         # the embedded license public key
```

{% hint style="info" %}
The same module verifies the runtime artifact itself — `release_public_key()`, `verify_manifest(...)`, and `verify_artifact(path, expected_sha256)` — a separate signature from the license. See [Verify the runtime signature](/security/runtime-signature-verification.md) and [Three trust anchors](/security/trust-anchors.md).
{% endhint %}

## Verify from the CLI

There is no standalone `telys verify` command. License and runtime verification happen together:

```bash
telys runtime verify
```

This checks the installed runtime's manifest signature and its bundled `license.jwt` offline, using the same rules as the Python API — the fastest way to confirm a machine is correctly licensed.

## Enforcing a license when serving

A Telys server can require a valid license at boot. Pass the token and enable enforcement:

```bash
telys serve --path ./memory --host 0.0.0.0 --port 8099 \
  --access-token "$TELYS_ACCESS_TOKEN" \
  --license "$TELYS_LICENSE" --require-license
```

With `--require-license`, the server verifies a `products.telys` version-2 license offline before accepting connections, and refuses to start otherwise. Provide the token through `$TELYS_LICENSE`.

## Overriding issuer, audience, and key

For air-gapped or self-managed deployments, override the expected values through the environment. Defaults are correct for the public service; override only if you know why.

| Variable                         | Default                         | Effect                                  |
| -------------------------------- | ------------------------------- | --------------------------------------- |
| `TELYS_LICENSE_ISSUER`           | `https://license.algenta.ai`    | Expected `iss` claim                    |
| `TELYS_LICENSE_AUDIENCE`         | `telys-runtime,algenta-runtime` | Accepted `aud` values (comma-separated) |
| `TELYS_LICENSE_PUBKEY` / `_FILE` | embedded PEM                    | License verification key override       |
| `TELYS_LICENSE`                  | —                               | License token for `telys serve`         |

## Next steps

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Verify the runtime signature</strong></td><td>Check the signed engine, not just the license.</td><td><a href="/pages/as3JvHboA5RxokqNHpAw">/pages/as3JvHboA5RxokqNHpAw</a></td></tr><tr><td><strong>Three trust anchors</strong></td><td>How release, license, and device keys fit together.</td><td><a href="/pages/IfZ7h0ml3OjlVuNi4tGX">/pages/IfZ7h0ml3OjlVuNi4tGX</a></td></tr><tr><td><strong>Signature verification failures</strong></td><td>Diagnose a rejected license or manifest.</td><td><a href="/pages/0eykLEyLKnupmpNlVgH9">/pages/0eykLEyLKnupmpNlVgH9</a></td></tr></tbody></table>

Next: [Verify the runtime signature](/security/runtime-signature-verification.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.telys.ai/licensing/offline-licenses.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
