> 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

The Telys license is a signed, offline-verifiable JWT — this page explains its claims, how telys.verify and telys runtime verify check it locally, and why it works with no network.

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="/security/runtime-signature-verification.md">Verify the runtime</a></td></tr><tr><td><strong>Three trust anchors</strong></td><td>How release, license, and device keys fit together.</td><td><a href="/security/trust-anchors.md">Trust anchors</a></td></tr><tr><td><strong>Signature verification failures</strong></td><td>Diagnose a rejected license or manifest.</td><td><a href="/troubleshooting/signature-verification.md">Signature verification</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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
