When we launched Chiave, we described what it does: generate license keys, track activations, handle Stripe billing, and keep tenant secrets safe — all hosted, so you do not run a licensing server yourself. That article answered what. This one answers how. If you are evaluating a hosted licensing platform, the architecture is not a detail; it is the product. Where your customer data lives, how your payment secrets are stored, and whether you can prove who did what — those decisions are made once, at the schema level, and you inherit them forever.
So here is the honest engineering tour: how Chiave isolates one company's data from another's, how it stores secrets it can never afford to leak, and how it records every consequential action. No marketing gloss — just the design choices and the trade-offs behind them.
One Database, Many Tenants
Chiave is multi-tenant: many independent companies share one running system. The hard question for any multi-tenant system is isolation — making sure tenant A can never see tenant B's customers, products, or licenses. There are two common ways to do it. You can give every tenant their own database (strong isolation, painful operations — every schema migration runs N times, and provisioning a new customer means provisioning infrastructure). Or you can share one schema and scope every row to a tenant. Chiave takes the second approach, and enforces it rigorously.
Every operational table — customers, products, licenses, activations, API keys, and the audit log — carries an indexed tenant_id column. Uniqueness is always composite with the tenant, never global. A license key is unique per tenant (uk_license_key_tenant), not across the whole platform; the same is true for customer emails (uk_customer_tenant_email) and product slugs (uk_product_tenant_slug). Two unrelated companies can both have a customer named jane@example.com or a product called pro without ever colliding, because the database treats those values as meaningful only inside a single tenant.
Tenant Resolution Happens Before Your Code Runs
A tenant middleware layer resolves which tenant a request belongs to — from the dashboard session or the API key on an inbound request — and pins the resolved tenant_id onto the request before any handler executes. From there, every query is scoped: a license lookup is License.tenant_id == tenant.id AND License.license_key == …, never a bare key lookup. Isolation is not a convention developers have to remember; it is the shape of every query in the codebase.
| Isolation model | Database-per-tenant | Row-level (Chiave) |
|---|---|---|
| Migration cost | Runs once per tenant | One migration, all tenants |
| New-tenant provisioning | Spin up a database | Insert a row |
| Cross-tenant leakage risk | Physically separate | Prevented by scoped queries + constraints |
| Operational overhead | High | Low |
Row-level isolation puts the responsibility on the application to never issue an unscoped query — which is exactly why tenant scoping lives in the middleware and the query layer rather than being sprinkled through individual endpoints. The constraints are the safety net: even a buggy query cannot make two tenants' keys collide.
Secrets That Stay Secret
To run billing for you, Chiave has to hold things that must never leak: your Stripe secret key, your Stripe webhook signing secret, and (if you send email) your SMTP password. Storing those in plaintext would be negligent. Storing them encrypted, but logging them or returning them in an API response, would be just as bad in practice.
Chiave encrypts these values at rest with Fernet (symmetric authenticated encryption from the Python cryptography library — AES in CBC mode with an HMAC for integrity). The encrypted columns are suffixed _enc in the schema (stripe_secret_key_enc, stripe_webhook_secret_enc, email_password_enc), and the encryption key itself lives in the environment, never in the database — so a database dump alone reveals nothing usable.
The part that matters most is what happens on the way out. Decrypted secrets are used internally to call Stripe or send mail, and that is it. They are never written to logs, and the dashboard API never returns them. When the settings page needs to show whether a secret is configured, it returns a boolean — has_stripe_secret, has_stripe_webhook, has_email_password — not the value. Your Stripe publishable key is stored in plain text, because it is designed to be public; everything sensitive is encrypted.
Application-Layer Encryption Means Key Management Is Real
Because the encryption key lives in the environment, rotating it is an operational task, not a checkbox — rotate the key and existing ciphertext must be re-encrypted. We chose application-layer Fernet over leaning entirely on at-rest disk encryption because it protects secrets even from a leaked database backup. The cost is that key custody and rotation are responsibilities we take on deliberately, rather than pretending they do not exist.
Every Action, On the Record
If you sell software, you will eventually need to answer a question like “why was this customer's license revoked, and who did it?” Chiave answers that with a dedicated audit_log table. Every entry records the tenant, the acting user, the action, the target (type and id), the originating IP address, a JSON details blob for context, and a timestamp.
More than twenty event types are recorded today, covering the actions that actually have consequences:
- License lifecycle: created (manually and via API), revoked, activated, deactivated, bulk-revoked, and exported — activation events capture the machine identifier in details.
- Catalog changes: products created, updated, activated, and deactivated; customers created.
- Account and billing: tenant provisioned, tier changed, settings updated, trial expired or upgraded, suspended, and reactivated.
Two design choices make the audit log trustworthy. First, the helper that writes audit rows is deliberately non-blocking: if a log write ever fails, it is caught and rolled back rather than failing the operation the user actually requested. Auditing observes; it never gets in the way of the work. Second, the log is not open to everyone — only Owner and Admin roles can read it, paginated, so a read-only viewer on the account cannot mine activity history.
License Keys and Honest Validation
Chiave keys look like CHV-XXXXX-XXXXX-XXXXX-XXXXX and are generated from a cryptographically secure random source. Here is where we are deliberately precise, because licensing vendors often blur this: Chiave keys are opaque random tokens, not cryptographically signed payloads. Validation is a scoped database lookup against the Chiave API — your app asks “is this key valid for this product?” and the server answers authoritatively, checking activation counts and machine fingerprints as it goes.
The practical implication: validation is online by design. That is a strength — you can revoke a key and have it take effect on the next check, track activations per machine, and deactivate a seat — and it is a constraint, because it means a network round-trip. For software that runs offline, the pattern is to cache the last successful validation and honor a configurable grace period, rather than to verify a signature with no server contact. If your model requires fully offline, signature-based validation with zero server dependency, that is a different architecture, and it is worth knowing the difference before you choose a platform.
The Stack Underneath
API & Data
FastAPI with SQLAlchemy over MySQL. Async request handling, typed models, and the tenant-scoped query layer described above.
Auth & Hardening
JWT sessions with Argon2 password hashing. Redis backs JWT revocation and brute-force tracking, so abusive clients are throttled.
Billing
Stripe handles checkout and subscriptions; signed webhooks drive license creation, with the webhook secret encrypted at rest.
None of these are exotic choices, and that is the point. A licensing system is infrastructure your customers depend on at startup; it should be built from boring, well-understood parts and isolated correctly, not from clever tricks. The interesting work is in the boundaries — tenant scoping, secret handling, and auditability — not in the framework list.
Why This Matters for You
If you are deciding whether to build licensing in-house or host it, the architecture above is the comparison you are actually making. Building it yourself means owning multi-tenant isolation, secret encryption, an audit trail, and the validation API — correctly, and forever. Hosting with Chiave means inheriting those decisions and spending your engineering time on the product people pay for. For a side-by-side with a dedicated licensing vendor, see Chiave vs Keygen, and if you want the integration walkthrough, the setup guide shows the single startup call that wires it into your app.
Licensing Infrastructure You Do Not Have to Build
Multi-tenant isolation, encrypted secrets, and a full audit trail — hosted, with a 30-day free trial and no credit card required.
Explore Chiave