Remote Eaze
Security

License Security

Cryptographic license integrity, tenant provisioning, HMAC-SHA256 tamper detection, and the license data model.

The license is the foundational security and provisioning primitive. Creating a license provisions a new tenant: it seeds the admin role, head office branch, and base currency in a single atomic transaction. Every authenticated request validates the tenant's license for integrity, expiry, and active status.

License Data Model

Identity

FieldTypeNotes
idStringFormat: XXXX-YYYY-ZZZZ (3 segments, 4 chars each). Characters from set ABCDEFGHJKLMNPQRSTUVWXYZ23456789 (excludes ambiguous 0, 1, O, I). Generated with crypto.randomBytes.
companyNameString2–100 chars
companyAbbreviationStringUnique. Auto-generated 3–4 char CNA from company name.
slugStringUnique. Auto-generated from companyName via slugify, or user override.
logoString?URL

Contact Information (all optional)

companyAddress, companyContactEmail, companyContactPhone, contactPersonName, contactPersonEmail, contactPersonPhone

Contract Terms (signed fields)

These fields are protected by the HMAC-SHA256 signature. Changing any of them requires re-signing by a System Admin.

FieldTypeNotes
licenseCodeStringUnique. HMAC-SHA256 signature (base64) — the integrity seal.
licenseExpiryDateDateEvaluated at end-of-day in the tenant's timezone.
modulesString[]Array of module codes. Currently only CORE.
timezoneStringIANA timezone (e.g., Africa/Nairobi).

Financial Configuration

FieldDefaultNotes
financialYearCycle20251231M1231Format: ccyymmddMnndd
accountingTypeACCRUALEnum: CASH or ACCRUAL

Password & Session Policies

FieldDefaultRange
passwordMinLength88–128
passwordMinNumber10–10
passwordMinUppercase10–10
passwordMinLowercase10–10
passwordMinSpecialChar10–10
passwordChangeInterval90 days0–365
inactivityTimeout600 seconds60–86,400

System Fields

FieldTypeNotes
customFieldsJSON?GIN-indexed
versionIntIncremented on every update (optimistic concurrency)
isActiveBooleanDefault true
deletedAtDateTime?Soft delete marker

Cryptographic Integrity

Signing

Payload:  {slug}|{expiryDate}|{sortedModules}|{timezone}
Example:  acme-bank|2026-12-31|CORE|Africa/Nairobi

Algorithm: HMAC-SHA256
Key:       LICENSE_SECRET_KEY (env, minimum 32 chars)
Encoding:  Base64
Stored in: licenseCode field (unique constraint)

Only the contract terms (slug, expiry, modules, timezone) are signed. Configuration fields (logo, contacts, password policies, financial config) can be changed by tenant admins without re-signing.

Verification

On every license access:

  1. Recompute HMAC-SHA256 from current DB fields
  2. Compare with stored licenseCode using crypto.timingSafeEqual (constant-time, prevents timing attacks)
  3. If buffer lengths differ, comparison fails safely (caught via try/catch)

Tamper Response

On integrity mismatch:

  • Redis key license:blocked:{id} set to "1" with 5-minute TTL
  • All subsequent requests for that license get immediate 403 LICENSE_TAMPERED (block checked before cache or DB)
  • HIGH sensitivity audit event logged
  • Block is cleared only when a System Admin performs a legitimate contract update (re-signing)

Redis Caching Strategy

KeyTTLPurpose
license:data:{id}Dynamic: min(3600, max(60, secondsUntilExpiry))Cached license data (avoids DB hit per request)
license:blocked:{id}300 seconds (5 minutes)Tamper block flag (checked first, always)

Cache invalidation: Both keys are cleared on contract updates and deletion. Config updates only clear the data cache (no re-signing involved).

API Endpoints

All routes under /api/v1/licenses. All require authentication.

MethodPathAccessDescription
GET/System Admin (L0)Paginated list with filters (search, isActive, expiresWithinDays, module). Returns summary stats: { total, active, inactive, expiringSoon }. No integrity checks per record.
POST/System Admin (L0)Full tenant provisioning (see below).
GET/:idSystem Admin or own tenantView license with full integrity check. Expiry validation disabled for viewing (admins can see expired licenses). Tenant isolation: non-L0 users can only access their own tenant.
PATCH/:id/contractSystem Admin (L0)Update contract terms (expiry, modules, isActive). Triggers re-signing. Clears cache and block keys.
PATCH/:id/configSystem Admin or Tenant Admin (update_config)Update operational config (logo, contacts, password policies, financial config, custom fields). Clears cache only.
DELETE/:idSystem Admin (L0)Soft delete: sets isActive=false, deletedAt=now(), increments version. Clears all Redis keys.

List Query Parameters

search (companyName/slug/abbreviation), isActive, expiresWithinDays, module, sortBy (createdAt/licenseExpiryDate/companyName), sortOrder, page, limit (1–100, default 20). Also supports custom field filter passthrough.

Tenant Provisioning

Creating a license (POST /) triggers a multi-step atomic transaction:

  1. Validate reference data — checks that the head office country exists in Nation and base currency exists in Currency
  2. Generate unique slug — from company name (or user override), with counter suffix on collision
  3. Generate CNA — 3–4 character Company Name Abbreviation, checked for uniqueness (with race-condition guard inside the transaction)
  4. Generate license IDXXXX-YYYY-ZZZZ format using crypto.randomBytes, retry loop (max 3) for collisions
  5. Sign license data — HMAC-SHA256 over contract terms

Within the transaction (all-or-nothing):

  • Create the License record
  • Seed the base currency as a TenantCurrency with 1:1 exchange rates
  • Seed the head office branch (code format: {CNA}-{alpha3}-000-0000, type: LEAD)
  • Seed the TENANT_ADMIN role with full permissions from the TENANT_ADMIN_DEFINITION blueprint (creates Role + PermissionMatrix + PermissionAction entries for all 37 non-license entities, plus read/update_config for license)
  • Create audit log entries for each provisioned entity

Returns: sanitized license (no licenseCode), tenant admin role, head office branch, base currency.

CNA Generation Algorithm

The Company Name Abbreviation is auto-generated as a unique 3–4 character code:

  • 1 word: First 3 consonants (consonant-start) or first letter + 2 consonants (vowel-start), with fallbacks up to 4 chars
  • 2 words: AA+B, fallbacks A+BB, AA+BB
  • 3+ words: First letter of each word, fallbacks with extra chars
  • Strips corporate suffixes: Ltd, Limited, Inc, Corp, PLC, LLC, etc.
  • Multiple candidates generated and checked against DB for first available

Access Control

System Administrator (Layer 0)

  • Cross-tenant license management
  • Create, delete, and update contract terms (triggers re-signing)
  • Config updates on any tenant
  • Full list visibility across all tenants

Tenant Administrator (Layer 1)

  • Isolated to own license only (user.tenantId === license.id)
  • Can update operational config (logo, contacts, password policies, financial settings)
  • Read-only access to contract terms
  • No cross-tenant visibility

Security Event Classification

Error CodeHTTPTriggerResponse
LICENSE_TAMPERED403HMAC signature mismatch5-minute block + HIGH audit event
LICENSE_EXPIRED402Past end-of-day in tenant timezoneAccess denied with renewal guidance
LICENSE_INACTIVE403isActive === falseAccess denied

On this page