CertifiEd

CertifiEd documentation

CertifiEd is a cryptographic licensing platform for on-prem software. A license is a self-contained token signed with Ed25519: your application verifies it locally, with no round-trip to the server. Below is the map of every section plus a condensed architecture tour.

The problem

On-prem software shipped to customers needs protection against unlicensed use — without permanent internet access and without handing control over to somebody else's cloud.

How the solution works

CertifiEd issues cryptographically signed licenses (Ed25519). The product configuration — feature flags and limits — lives inside the signed token instead of being served over an API: the client application validates the license locally against the public key and keeps working offline for up to 30 days.

  • Fully self-hosted. PostgreSQL, MinIO, observability — all on your own servers. No Cloud KMS, no managed services, no SaaS billers.
  • Multitenant from day one. A company tree of arbitrary depth (ltree): the root is a direct customer, descendants are sub-customers and resellers. A role granted on a node applies to the entire subtree.
  • Offline is the norm. Heartbeats are desirable but not mandatory; the grace window goes up to 30 days.
  • Audit everything. Every mutation lands in audit_log.

Roles and scopes

RoleScope
OperatorGlobal (an Ofarandagon employee)
Owner / Admin / ViewerA company and its entire subtree

Glossary

TermMeaning
Template (LicenseTemplate)A product; template versions carry the JSON Schema of the config
LicenseAn issued signed instance for a company; key CFED-…, file .ced
ActivationBinding a license to a hardware fingerprint
HeartbeatA periodic check-in from the client application

Architecture

A monolith with clean boundaries — Clean Architecture, dependencies point strictly one way.

text
SharedKernel <- Domain <- Application <- Infrastructure <- Api                                                   <- Client (SDK, token format only)
  • SharedKernelResult<T>, Error, primitives. No dependencies.
  • Domain — entities, enums, value objects. No dependencies.
  • Application — use cases, interfaces (ISigner, repositories), DTOs.
  • Infrastructure — EF Core (Npgsql, snake_case, ltree), EncryptedFileSigner, WebhookDispatchWorker, SMTP.
  • Api — ASP.NET Core; two contours inside one process.
  • Client — the SDK, depending only on the token format.

Two API contours

ContourPrefixAuthenticationRate limit
Panel API/api/v1/panel/*certified.auth cookie or a PAT via Authorization: Bearer300 req/min per IP
Client API/api/v1/client/*public; mutations are HMAC-signed100 req/min per IP

Details live in the API reference.

Signing and keys

  • One Ed25519 key pair per template (NSec.Cryptography).
  • Private keys sit in files encrypted with AES-256-GCM; the master key comes from the CERTIFIED_MASTER_KEY environment variable.
  • Rotation: the new key becomes active, the old one rotating, then retired. On compromise a key is marked compromised and licenses are re-issued.

Data, background work, observability

  • PostgreSQL 16: UUIDv7, timestamptz, jsonb, ltree (companies.path) for subtree queries. Heartbeats are a candidate for monthly partitioning.
  • BackgroundService workers (no Hangfire in v1): webhook delivery with retries and the X-CertifiEd-Signature header, license expiry, heartbeat cleanup.
  • Serilog (compact JSON) plus OpenTelemetry (traces/metrics, OTLP optional); health endpoints /health, /health/live, /health/ready.

Deployment

text
[Caddy / nginx: TLS]   |-- panel.certified.example    -> panel static build   |-- portal.certified.example   -> customer portal   |-- certified.example          -> landing static build   `-- api.certified.example      -> CertifiEd.Api (Kestrel)
[PostgreSQL 16]   [MinIO: backups/export]   [Redis: optional]   [SMTP]

Cloudflare is edge only (TLS / WAF / DNS) — no Workers, no KV. All state stays inside your perimeter.

Environment variables

VariablePurpose
CERTIFIED_MASTER_KEYbase64, 32 bytes — encrypts the private signing keys
CERTIFIED_KEYS_DIRDirectory of encrypted keys — must be part of your backups
CERTIFIED_CORS_ORIGINSOrigins of the panel and the customer portal
ConnectionStrings__DefaultPostgreSQL connection string

Production checklist

  • Back up PostgreSQL (pg_dump + WAL) and CERTIFIED_KEYS_DIR.
  • Change the seeded operator password.
  • Rate limiting enabled: client 100/min, panel 300/min.
  • OTLP pointed at your own Grafana stack, alerting configured.
  • Partition heartbeats once the volume grows.

Where to go next