Docs

Licensing

Watch is free and Defend is a paid plan, issued by request. The WDL1 file format, offline verification, and renewal.

On this page

A Warden license is a small signed text file. Warden checks it offline when it starts. It never phones home to do so.

Price

The Watch license is free. Defend is a paid plan, and its licenses are issued by request; nothing is charged yet. See Pricing.

Plans

You choose the plan when you create a license. Both plans run for 365 days.

Planplan in the filefeatures in the filePrice
Watch"watch"["watch"]Free
Defend"defend-early"["watch", "defend"]A paid plan, issued by request

Watch is read-only: the scan, the event lane, the agents, cases, hunting and hardening proposals. It changes nothing in your accounts. Defend adds response plans: one passkey signature contains the attacker and closes the path they used, every step dry-run first, time-boxed and undoable. A Defend license turns Defend on; a keeper still signs it on in the console.

The charged Defend plan has the id "defend". A Defend license issued during the early access preview says "defend-early" in the file, so it is never mistaken for a charged one. It keeps Defend on until its own expiry.

Every license issued before these plans says "community". It keeps working as a Watch license, and its renewal is issued as "watch". A "defend" license issued at no cost renews as "defend-early". Any other license renews on its own plan while that plan is offered.

Any license, including the free Watch license, turns on changes. Defend needs a Defend license. Warden keeps watching in every license state.

The license page shows the expiry date and what stops then: changes, and Defend if the license carries it. The watch never stops. Renew before that date to keep them on.

What a license is

A license belongs to your account on this site and names one estate. An estate is the AWS accounts and EKS clusters one hub watches: a single account, or an organization’s accounts. A license carries:

  • the estate label you chose, and optionally the AWS account id of the hub;
  • the plan and the features it grants;
  • when it was issued, when it starts and when it expires;
  • an Ed25519 signature from us over all of the above.

The file is called warden.license. You can open it in any text editor. It is one line.

The file format (WDL1)

WDL1.<payload>.<signature>
  • <payload> is the base64url (no padding) encoding of a UTF-8 JSON object.
  • <signature> is the base64url (no padding) Ed25519 signature over the ASCII bytes of WDL1.<payload>, exactly as written in the file.

Payload fields

FieldTypeMeaning
vnumberFormat version. Always 1.
kidstringId of the key that signed the license.
license_idstringUUID of this license.
account_idstringOpaque id of the account that owns the license.
licenseestringName of the license holder.
estatestringThe estate label, 1 to 64 characters.
hub_account_idstring or nullThe hub’s AWS account id, exactly 12 digits, or null.
planstringThe plan id: "watch", "defend-early" or "defend"; "community" on licenses issued before these plans.
featuresarray of stringsWhat the license grants: ["watch"] or ["watch", "defend"].
issued_atstringWhen the license was issued. RFC 3339, UTC.
not_beforestringThe license is not valid before this time. RFC 3339, UTC.
expires_atstringThe license is not valid at or after this time. RFC 3339, UTC.

An example payload, before encoding:

{
  "v": 1,
  "kid": "wd1-5c0f2a9e7d41b386",
  "license_id": "0f6b8a52-3c1d-4e7a-9b2f-6d4c8e1a7b30",
  "account_id": "a3e9c2d4-7b16-4f08-8c5a-2e9d1b6f4a73",
  "licensee": "Example Ltd",
  "estate": "production",
  "hub_account_id": "123456789012",
  "plan": "watch",
  "features": ["watch"],
  "issued_at": "2026-10-02T12:00:00Z",
  "not_before": "2026-10-02T11:55:00Z",
  "expires_at": "2027-10-02T12:00:00Z"
}

The values above are illustrative. They do not belong to a real license.

The dashboard writes not_before five minutes before issued_at, so a new license is not rejected by a clock that runs a little slow. expires_at is issued_at plus the plan’s term. licensee is the name on your account when the license was issued.

Verification

A verifier does these steps in order and stops at the first failure:

  1. Reject input larger than 16 KiB (16,384 bytes of UTF-8). Remove spaces, tabs, carriage returns and line feeds at either end, and nothing else: a byte order mark or a no-break space makes the file invalid. Split the text on . into exactly three parts.
  2. Check that the first part is WDL1.
  3. Decode the payload. Reject it if it is not valid UTF-8 holding one strict JSON object, or if v is not 1. Strict means no key twice in one object, no byte order mark, nothing after the object, no lone surrogate and no more than 16 levels of nesting. Unknown versions are rejected. The signature must decode to exactly 64 bytes.
  4. Look up kid in the trusted key list. Reject unknown keys.
  5. Verify the Ed25519 signature over the bytes of WDL1.<payload> as written. Its scalar S must be below the group order, so each license has exactly one valid signature.
  6. Check that every field above is present and well formed. Unknown fields are ignored. The term, expires_at minus issued_at, must be at most 400 days.
  7. If the key has a not_after time, check that issued_at is not later than it.
  8. Check the time: not_before <= now < expires_at. A clock that gives no valid time fails the check.

Nothing in the payload is trusted until step 5 has passed.

You can run these steps yourself, in your browser, on the verify page. Nothing you paste there is uploaded.

License states

Warden shows one of five states, in the console, in warden license and in the first line setup prints.

StateMeaning
validA license checks out and has more than 30 days left.
expiringA license checks out and has 30 days or fewer left. The digest and the license page count the days down.
expiredThe license has passed its expires_at. Changes and Defend are off; the watch continues.
invalidA license was given and was refused. The reason is one of the names below.
unlicensedNo license is installed. The watch continues.

The watch never depends on the license. Changes need a license in the valid or expiring state. A Defend license also turns Defend on; a keeper still signs it on. After a Defend license expires, a keeper may still renew a live containment for 72 hours, so a lapse cannot free an intruder in the middle of a response. New Defend work waits for a valid license.

From 90 days before the built-in keys’ horizon, Warden raises a low-severity notice so you can adopt a release that carries newer keys. A license that is already issued keeps working until it expires.

Why a license is refused

An invalid state names one of these reasons. The first twelve are the verification steps above; the last two are Warden’s own.

ReasonWhen
too_largeThe file is larger than 16 KiB.
malformedIt does not split into three parts on ..
bad_prefixThe first part is not WDL1.
bad_payloadThe payload is not one strict JSON object in UTF-8.
unsupported_versionv is not 1.
unknown_keykid is not in the built-in key list.
key_retiredThe key’s not_after is earlier than issued_at.
bad_signature_formatThe signature is not exactly 64 bytes, or its scalar is out of range.
bad_signatureThe signature does not verify.
invalid_fieldsA field is missing or malformed, or the term is longer than 400 days.
not_yet_validThe time is before not_before.
expiredThe time is at or after expires_at.
wrong_hub_accountThe license names a hub account other than the one this install runs in. The watch installs without it.
keys_unusableThis release’s built-in key list does not parse.

Checking a license on the command line

warden license
warden license check <file> [--hub <12 digits>]

warden license prints the license this install’s ledger holds, its key and what its state turns off. warden license check verifies a file offline, with the built-in keys, and with --hub also checks the hub account it names.

Public keys

We publish the keys we sign with at /.well-known/wardensec/license-keys.json:

{
  "keys": [
    {
      "kid": "<key id>",
      "alg": "Ed25519",
      "public_key": "<base64url of the raw 32-byte public key>",
      "not_after": "<RFC 3339 UTC time>"
    }
  ]
}

not_after is the last moment a key may issue: licenses issued after it are not trusted under that key, and licenses issued before it keep working until they expire. Every key has one. Each Warden release sets it no more than two years ahead, and we publish a new key in a release before we sign with it. Because no license may run longer than 400 days, nothing a key signs is valid more than 400 days after its not_after, even if the key were stolen.

Warden carries the same list built in. Today it holds two keys, wd1-6540bc2b7d5f5437 and wd1-d6becec2301ceb35. It never fetches the list. The published copy exists so that you can check a license without trusting the product. A new signing key is added to the product in a release before we sign with it, so a license we issue is never signed with a key your install does not know.

Offline means offline

No license server, no fetch, no revocation list. The watch never depends on the license.

Because a license is checked offline, nothing can switch it off remotely. A retired license file keeps working until it expires. Retiring a license in the dashboard only marks it as retired there.

Getting a license

  1. Create an account on this site with a passkey. There are no passwords.
  2. Create a license. Give it an estate label and, if you like, the 12-digit AWS account id of the hub.
  3. Download warden.license, or copy its contents.

Each account can hold up to 10 active licenses. Expired, renewed and retired licenses do not count. An account can create or renew up to 10 licenses a day.

Renewing

A license lasts 365 days. To renew, open the license in the dashboard and choose Renew. You get a new file with a new license id, for the same estate and hub account, valid for another 365 days. Replace the old file with the new one. The old license is marked as renewed; its file keeps working until it expires.

Retiring

Choose Retire on a license you no longer use. It is marked as retired in the dashboard and stops counting toward the limit. The file itself keeps working until it expires, because nothing checks it over the network.

What a license does not do

  • It does not phone home, and nothing checks it over the network.
  • It does not report usage, and it does not count accounts or clusters.
  • It cannot be revoked remotely. It is valid until it expires.
  • It does not contain any secret. It is safe to keep with your configuration.