How Licensing Works

AppProfileSafe is available in two editions: Community Edition (free, no license required) and Enterprise Edition (subscription license). Enterprise license validation runs on every application start (GUI and CLI) and verifies three things: the license file has a valid cryptographic signature, the subscription has not expired beyond the grace period, and the environment (AD domain or Azure tenant) matches the licensed scope.


Community vs. Enterprise Edition

The Community Edition provides the full GUI experience at no cost. The Enterprise Edition adds automation, compliance, and integration features for organizations that need them.

Feature Community (free) Enterprise (licensed)
GUI Export & Import
Application Definitions (create, edit)
Mapping Editor
Simulation & DryRun
Preflight Validation
Local Audit Log (hash-chained)
Run Reports (JSON)
CLI (AppProfileSafe.CLI.exe)
SIEM & Webhook Event Delivery
Compliance Reports (HTML)

In Community Edition, events are still written to the local event pipeline queue, but delivery to external SIEM and webhook endpoints is not performed. Upgrading to Enterprise at any time enables delivery of all queued events.

The License tile on the Dashboard shows the current edition and license status. Community Edition is shown when no license file is present, when the license is invalid, or when the Enterprise subscription has expired beyond the grace period.


License File Structure

License.json contains the following fields:

Field Description Example
ProductName Must be AppProfileSafe "AppProfileSafe"
CustomerName Name of the licensee "Contoso Ltd."
SubscriptionEndDateUtc ISO 8601 UTC timestamp marking the end of the subscription "2027-03-31T23:59:59Z"
LicenseId Unique license identifier "LIC-2026-0042"
LicensedDomainOrTenant AD DNS domain name or Azure AD Tenant ID (GUID) "contoso.com" or "a1b2c3d4-..."
Signature Base64-encoded RSA-PSS signature "MIIE..."


Validation Sequence

When the application starts, the following steps are performed in order:

  1. File check — Verify that License.json and AppProfileSafe.pem exist at the configured paths. If either file is missing, the GUI starts in Community Edition. The CLI exits with code 3.
  2. JSON parsing — Deserialize License.json and parse the SubscriptionEndDateUtc field.
  3. Signature verification — Build the canonical signature input from the five signed fields (ProductName, CustomerName, SubscriptionEndDateUtc, LicenseId, LicensedDomainOrTenant), then verify the RSA-PSS signature using SHA-256 and the public key.
  4. Expiration check — Determine whether the subscription is active, expiring soon (≤ 30 days), in the grace period (0–30 days past expiry), or expired beyond grace (> 30 days past expiry).
  5. Environment binding — Match LicensedDomainOrTenant against the current environment (AD domain or Azure tenant).

If any step fails, the GUI falls back to Community Edition and displays the reason on the License tile. In CLI mode, exit code 3 is returned.


Signature Input Format

The signature input is a deterministic string built from the five signed fields, each on its own line as Key=Value, separated by \n (no trailing newline):

ProductName=AppProfileSafe
CustomerName=Contoso Ltd.
SubscriptionEndDateUtc=2027-03-31T23:59:59Z
LicenseId=LIC-2026-0042
LicensedDomainOrTenant=contoso.com

The SubscriptionEndDateUtc value is used exactly as stored in the JSON file (no re-formatting) to ensure consistent signature verification. The signature algorithm is RSA-PSS with SHA-256.


Environment Binding

The LicensedDomainOrTenant field is matched against the running environment using one of two strategies, automatically selected by format:

Format Detection Method Match Rule
GUID (Azure Tenant ID) Resolved via dsregcmd /status Exact match (case-insensitive)
Domain name (AD DNS) Resolved from the machine's domain membership Dot-separated suffix match: sub.contoso.com matches contoso.com

The suffix match for AD domains means a license for contoso.com is valid on machines joined to contoso.com, eu.contoso.com, or any subdomain.