License Management & Feature Gating
How license enforcement works: what your signed license covers, what each state allows, and how to watch expiry and your user count.
On this page
- Overview
- Prerequisites
- The License Page
- Apply or Renew a License
- Read-Only State
- Features and What They Unlock
- User and Directory Source Limits
- User limit
- Licenses that count identities
- Directory source limit
- Prometheus Metrics
- Recommended alerting rules
- Troubleshooting
- Changes are refused while the license is read-only
- A feature is refused as not licensed
- The server logs "Identity count exceeds license limit"
- The banner says "No license applied" after you imported one
- The server refuses to start
Overview
Every deployment runs on a signed license file from GraphnAI. The license sets three things:
- Features: which paid capabilities are unlocked, such as Graphne, Select Fire and Detections.
- Limits: how many users and directory sources it covers. Licenses issued before the user count cover identities instead.
- Expiry: when it ends. A preview license also has an activation window that starts at your first sync.
GraphnAI checks the license at startup, once an hour, and whenever you apply a new one. A missing or expired license never stops the server. The platform turns read-only instead: you can browse everything, but collection and changes stop until you apply a valid license.
The health probes (/health, /ready) and the Prometheus endpoint (/metrics) don't depend on the license. Your orchestration and monitoring keep working in every license state.
For what each plan includes and how locked features look, see Licensing & Plans. For the preview trial clock, see Preview & License Lifecycle.
Prerequisites
- A license file: GraphnAI issues it as
license.key. Your deployment bundle includes one. - Admin role to open the License page and apply a license. Every signed-in user sees the license banner.
The License Page
Open Admin > License. The Current license card shows your plan as a badge at the top right: Preview, Design Partner, Enterprise, Community, Exposure or Complete. Before you import a license, the badge says "No license".
| Row | What it shows |
|---|---|
| Status | Active, or Read-only |
| Activated | Preview licenses only. The date of your first sync, or "Not yet. Starts at the first sync." |
| Expires | The date the license ends, or "Never". For a preview, it's the earlier of the activation window's end and the license's own end date. |
| Days left | Days until the license expires. A preview shows a meter of the days left in its window. |
| Users | Enabled user accounts against the license limit, with a meter. A license with no limit shows the count and "No limit". Over a paid license's limit, the row reads "Over your license. Collection continues, and the difference is settled at renewal." While the count is pending, it reads "Counting users…". |
| Identities | Licenses issued before the user count only. This row replaces Users. It shows the identity count against the limit, with a meter, and "Over plan" when the count is above it. |
| Directory sources | Active Directory domains plus distinct Entra ID tenants, against the license limit |
| Source | "Uploaded license file", or "No license applied" |
Under the rows, a badge for each feature shows a check when your license includes it and a lock when it doesn't. Hover a badge to see whether your plan includes it.
When the license has expired or none is applied, the apply card also has a Get a license link to graphnai.com/pricing.
The page also holds Apply a license, Support access and Usage reporting.
Apply or Renew a License
A new license takes effect at once, with no restart. It works from the read-only state too.
- Open Admin > License.
- Under Apply a license, select Choose your license file, or drag the file onto the box.
- Select Apply.
A "License applied" message confirms it. The banner clears, locked features unlock, and collection resumes at the next sync.
If the new license gives you less than your current one, the Apply a smaller license? dialog lists what changes:
- Removes: features the new license doesn't include
- Expires sooner: the new, earlier expiry date
- Lower user limit (or Lower identity limit): the old and new limits
- New limit: shown when a license with a user limit replaces an unlimited one, for example "1,000 users (was unlimited)"
Select Apply anyway to continue, or Cancel to keep your current license.
The applied license is stored in the database and survives restarts. You can also import a license during first-run setup. See Quick Start: Self-Hosted Deployment.
Read-Only State
The platform turns read-only for one of three reasons. The banner at the top of every page names it.
| Banner | Cause | What to do |
|---|---|---|
| Your preview has ended. | The preview's activation window has closed. | Apply a new license. |
| Your license has expired. | The license's end date has passed. | Apply a renewed license. |
| No license applied. | No license was ever imported, or the stored license failed its signature check. | Import your license file. |
Administrators see a Get a license link beside Apply license (or Import license) on this banner. It opens graphnai.com/pricing.
GraphnAI checks expiry once an hour, so read-only begins at the first check after the expiry time.
While the license is read-only:
- Still works: every page and every read, including the graph, dashboards, findings and inventory. You can still sign in and out, and manage sessions, users, identity providers and directory sign-in (LDAP). Applying a license, undoing an action you already ran, the automation kill switch, support access and diagnostics keep working too.
- Paused: new directory syncs from bridges and Entra ID, and telemetry ingestion. A sync that's already running finishes.
- Blocked: every other change. That covers Select Fire actions, simulations, sync triggers, and edits to rules and settings.
Controls you can't use show a tooltip: "Read-only until a valid license is applied. An administrator can apply one on the License page."
Nothing is deleted or hidden. See What read-only means for the "Posture as of" chip the banner shows.
Features and What They Unlock
Each feature is a flag in the license. The server checks the flag on every request, so a license you apply unlocks features at once. The flag names appear in the Prometheus metrics.
| Feature | Flag | What it unlocks |
|---|---|---|
| Graphne | ai_agent |
Graphne, investigations, and AI provider setup |
| Telemetry | telemetry |
Windows logon event ingestion and the Telemetry admin page |
| Select Fire | remediation |
Fix plans and their execution, remediation credentials, and automatic undo |
| Full-Auto | autonomy |
Full-Auto settings and escalation channels |
| Simulations | simulations |
Creating and clearing what-if simulations |
| Detections | itdr |
ITDR detection alerts, alert status changes and triage policies |
| Delegation Risk | delegation_analysis |
The Delegation Risk page |
| Critical Junctions | junction_analysis |
The Critical Junctions page |
| Exports | exports |
Reserved. Nothing uses it yet. |
| Access certifications | certifications |
Reserved. Nothing uses it yet. |
Some surfaces never depend on features: signing in, users and identity providers, the graph, dashboards, posture, inventory and directory sync. Undo of an action you already ran and the automation kill switch never depend on features either. Both keep working while the license is read-only.
Detection and Critical Junction analysis keep running when their feature is locked. The locked page shows how many alerts or junctions are waiting. See Licensing & Plans.
User and Directory Source Limits
User limit
GraphnAI counts enabled user accounts each time an Active Directory or Entra ID sync finishes. A user synced from AD to Entra ID counts once. Computers, groups, guests, disabled accounts, gMSA, sMSA and dMSA accounts, service principals and the other objects in the graph don't count. A limit of 0 means no limit. To verify the number, see How the user count is measured.
The license sets one of two modes:
- Soft: collection never pauses. This is every paid license. Administrators see a dismissible banner, and the License page row reads "Over your license". The banner comes back if the count grows further. The difference is settled at renewal. The server logs "Identity count exceeds license limit" at most once an hour, and a counter records every over-limit sync.
- Enforced: Community Edition. It allows 1,000 users. A 14-day grace window starts at the first over-limit sync, then new collection pauses. The banner counts down to the pause. See Community Edition.
A preview license has no user limit. Its Users row shows the count.
Licenses that count identities
A license issued before the user count counts every directory object in the graph: users, groups, computers, service accounts, OUs, containers and the rest. It has the same two modes. Its row reads Identities, its banners say "identities", and "Over plan" marks a count above the limit. See Licenses that count identities.
Directory source limit
A directory source is one Active Directory domain or one distinct Entra ID tenant. When the license sets a limit, GraphnAI refuses a new source beyond it: "The current plan covers N directory sources. Remove one or upgrade to add another."
Prometheus Metrics
The platform publishes these license metrics at /metrics. It refreshes them at startup, once an hour, and whenever a license is applied.
| Metric | Type | Description |
|---|---|---|
graphnai_license_effective_expires_at |
Gauge | When the license stops working, as a Unix timestamp. For a preview it's the earlier of the window end and the license end date. 0 means it never expires. Use this one for renewal alerts. |
graphnai_license_expires_at |
Gauge | The license's own end date, as a Unix timestamp. 0 means none. |
graphnai_license_activated_at |
Gauge | When a preview's window started, as a Unix timestamp. 0 until the first sync. |
graphnai_license_read_only |
Gauge | 1 while the license is read-only, 0 otherwise |
graphnai_license_tier{tier="..."} |
Gauge | 1 on the current plan (preview, design_partner, enterprise, community, exposure or complete), 0 on the others |
graphnai_license_feature_enabled{feature="..."} |
Gauge | 1 for each feature the license includes, 0 for the others |
graphnai_license_users_max |
Gauge | The user limit. 0 means no limit. |
graphnai_license_users_current |
Gauge | The enabled-user count at the last finished sync |
graphnai_license_identities_max |
Gauge | The identity limit on a license that counts identities. 0 means no limit, and it reads 0 on a user license. |
graphnai_license_identities_current |
Gauge | The identity count at the last finished sync. Updated only when the license sets a limit. |
graphnai_license_identities_cap_state |
Gauge | The state of whichever limit the license uses, enforced limits only: 0 under the limit, 1 in the grace window, 2 collection paused |
graphnai_license_cap_overage_events_total |
Counter | Syncs that finished above the limit |
graphnai_license_cap_persist_failures_total |
Counter | Failed writes of the grace-window state. The next sync retries. |
graphnai_license_domains_max |
Gauge | The directory source limit. 0 means no limit. |
graphnai_license_domains_current |
Gauge | Directory sources configured |
graphnai_license_applied_total{result="..."} |
Counter | License apply attempts: ok, downgrade_ack or rejected |
graphnai_license_clock_anomaly_total |
Counter | Times the server clock moved backwards by more than 26 hours |
Recommended alerting rules
Adapt the thresholds to how long your renewals take.
Alert when the license expires in 30 days or fewer:
- alert: LicenseExpiringSoon
expr: graphnai_license_effective_expires_at > 0 and (graphnai_license_effective_expires_at - time()) < 86400 * 30
for: 1h
labels:
severity: warning
annotations:
summary: "GraphnAI license expires in less than 30 days"
description: "Contact your account manager to renew."
Alert when the license expires in 7 days or fewer:
- alert: LicenseExpiringCritical
expr: graphnai_license_effective_expires_at > 0 and (graphnai_license_effective_expires_at - time()) < 86400 * 7
for: 15m
labels:
severity: critical
annotations:
summary: "GraphnAI license expires in less than 7 days"
description: "Collection and changes stop when it expires. Renew now."
Alert when the platform is read-only:
- alert: LicenseReadOnly
expr: graphnai_license_read_only == 1
for: 5m
labels:
severity: critical
annotations:
summary: "GraphnAI is read-only"
description: "Collection is paused until a valid license is applied on the License page."
Alert when the user count exceeds the licensed limit:
- alert: UserCountOverLicense
expr: graphnai_license_users_current > graphnai_license_users_max and graphnai_license_users_max > 0
for: 5m
labels:
severity: warning
annotations:
summary: "User count exceeds the license"
description: "{{ $value }} users counted. The difference is settled at renewal. Contact your account manager."
Troubleshooting
Changes are refused while the license is read-only
- Cause: The license is read-only. The banner says whether the preview ended, the license expired, or no license is applied.
- Fix: Ask your account manager for a new license file, then apply it. No restart is needed.
A feature is refused as not licensed
- Cause: Your license doesn't include that feature.
- Fix: Check the feature badges on Admin > License. If a feature you bought shows a lock, ask your account manager for a corrected license file.
The server logs "Identity count exceeds license limit"
- Cause: The last sync finished with more users (or, on an older license, identities) than the license covers.
- Fix: Compare Users (or Identities) with its limit on Admin > License. Disable or remove stale accounts and sync again, or ask for a higher limit. Under a soft limit, nothing else happens.
The banner says "No license applied" after you imported one
- Cause: The stored license failed its signature check at startup. The server logs "Applied license failed validation" and starts read-only.
- Fix: Apply the original, unedited
license.keyagain. The file is signed, and any change to it invalidates it.
The server refuses to start
A license problem alone never stops the server. The server log names the cause:
- "Legacy secret variable is set but this build no longer reads it": the environment still sets the retired license variable from an older deployment. Remove it and import the license file instead.
- "Failed to load license verification key": the public key the image ships with at
/app/license-verify.pubis missing, orLICENSE_VERIFY_KEY_FILEpoints to the wrong file. - "License resolution failed (store unreachable)": the server couldn't read its database. Check that ArangoDB is running.