Latch Vector

Multi-tenant identity

The boundary holds
even when the code forgets.

Every multi-tenant system promises isolation. Most of them enforce it in application code — which protects exactly the paths someone remembered to protect. We enforce it three times, and the innermost layer does not care whether your developers remembered.

Fig. 1 — Section through a tenant boundary. Watch the requests that clear the first wall: those are the bugs every system eventually ships, and the reason there is a second wall standing behind it.

Defence in depth

Three layers, in order of what fails first.

These are numbered because the order is real. Each one catches a different kind of mistake, and the later layers exist precisely because the earlier ones depend on human diligence.

Layer 1

Authorization in the service

Holding a permission says nothing about which customer it applies to. Every request carrying an organization id is checked against the scopes the caller was actually granted, and a token with no scope is refused rather than trusted. It fails closed.

Layer 2

Row-level security in the database

Layer 1 protects the paths that call it. A repository method added next year, a query built from a string, an endpoint that skips the service — none of those are covered. So the database enforces the same boundary itself: a query arriving without a tenant context returns nothing, not everything.

Layer 3

Constraints that make the wrong state unrepresentable

Composite foreign keys mean a row's tenant cannot disagree with the record it came from. Database triggers derive each node's position in the customer hierarchy, so it cannot be written incorrectly. The audit trail refuses UPDATE and DELETE outright — not in code, in the schema.

Measured, not asserted

Numbers we can show you.

Verified in the test suite or measured against a million-row database — including the tests themselves, which we check by breaking the fix and confirming they fail. Load figures come from runs whose responses were confirmed to be 200, because a benchmark counting rejections is measuring the wrong thing.

Isolation tests
115

Integration tests against a real PostgreSQL, not an emulated one.

Sustained
9,700 rps

Reads against 1,000,000 organizations, 500 concurrent clients, 45 ms median.

Access cut-off
~10 s

From disabling an account to its live tokens being refused, with no per-request database lookup.

Subtree lookup
0.1 ms

Index scan, unchanged by how deep a customer nests.

Official SDKs

Your team ships against this on the first afternoon.

Identity is the part of a build that looks like two weeks on the plan and turns into two quarters in the repository. Not because signing a token is hard — because tenancy, rotation, revocation, MFA and an audit trail that survives review are each small on their own and enormous together.

// Express — the whole integration
const verifier = new TokenVerifier({ issuer, audience });

app.get('/invoices', requireAuth(verifier), (req, res) => {
  res.json(invoices.forOwner(req.principal.uid));
});
Behind those lines: 99 source files, 15 schema migrations, 115 tests — none of which your team writes, reviews or maintains.
4

Checks on every token, none of them optional

Signature, issuer, audience, and token purpose. No SDK exposes a switch to turn any of them off. The audience check is the one that matters: a token minted for a different application is validly signed by a trusted issuer, so a signature check alone accepts it — and with it, every user of every other application on the platform.

0

Lines of cryptography you write

The SDKs wrap each ecosystem's established library rather than reimplementing RSA in four languages, which would be four times the attack surface for no benefit. What they add is that the correct verification is the default and the unsafe shortcuts are unreachable.

1

URL to configure

The signing keys are discovered from the issuer, not hardcoded, so a moved endpoint never becomes your outage. Keys are cached in memory; your API verifies locally and never calls us on the request path.

15 min

Access token lifetime, so revocation is not your problem

Refresh tokens rotate on every use, and presenting a rotated one is reported as the compromise it probably is — as a distinct error type your retry logic cannot silently swallow.

Built for how customers are actually shaped

A hospital group is not a flat list of users.

Neither is a holding company with separate legal entities, or a franchise with regional operators. Most identity products assume two levels and force everything else into custom fields.

Any depth, one concept

Company, legal entity, branch, department — each is a node with a parent. There is no separate "sub-organization" concept to reconcile, because two competing hierarchies is how cross-tenant bugs get written.

One admin role, three behaviours

A role grants reach — this node, or this node and everything below — not a level. The same role at the root, a branch, or a leaf produces "sees everything", "sees their company", and "sees only their department". Nothing assumes how deep a customer nests.

Your permissions, your namespace

Your application defines its own permission codes and we never interpret them. Two customers can both use report.read without colliding, because they are namespaced per application.

Tokens that reveal nothing extra

A token is issued for one audience and carries that audience's permissions only. Your backend never learns what a user is allowed to do inside somebody else's application.

At rest

Encrypted, and still searchable.

Emails and usernames are stored as AES-256-GCM ciphertext with a random IV, so a database dump cannot even reveal which rows share a value. Lookups still work, because each field carries a keyed index beside it.

-- what a stolen dump actually contains
email_encrypted  1YqK52pfPuNZHiEhA3l…   ← random IV, differs every write
email_hash       lbpIAQCb5PBl8qvfuBy…   ← HMAC-SHA256, keyed

-- the keyed hash is the point. a plain SHA-256 of an email
-- falls to a dictionary in minutes: the space of real addresses
-- is small and guessable. keyed, an attacker needs the key —
-- and the key does not live in the database.

-- uniqueness moves to the hash, because ciphertext differs on
-- every write and a constraint on it would accept duplicates.
UNIQUE (email_hash)

The trade is honest: exact matching survives, prefix search does not. Nothing in an authentication service needs to search for "everyone at @acme.com", so we spent that flexibility on the guarantee instead.

Accountability

An audit trail nobody can quietly edit.

Reading a patient's record is an event. So is exporting it, erasing it, granting someone a role, disabling a second factor — and every refused attempt to reach another customer's data.

Append-only in the schema

A database trigger refuses UPDATE and DELETE on the trail. Not application code — a compromised application credential, a direct database session, or a bug in our own migration are all refused identically. We know, because one of ours was.

Refusals are recorded too

An attempt to reach another tenant returns 403 and lands in the trail. Detecting attempted access — not only successful access — is what HIPAA §164.312(b) actually asks for.

The actor, not just the subject

Each entry records who performed the action, on whom, from which address. Resolved from the verified session rather than passed in, so an action cannot be attributed to the wrong person.

It survives erasure

A subject's identifying fields are scrubbed on request; the record of who erased them remains. Opaque ids are not personal data once the identifying fields are gone.

Where we stop

What buying this does not give you.

Compliance is a programme, not a feature. Any vendor who tells you their software makes you HIPAA compliant is selling you a sentence you cannot repeat to an auditor.

  • A Business Associate Agreement with your hosting provider and every subprocessor that touches protected health information.
  • A documented, periodic risk assessment, and a designated privacy and security officer.
  • An incident response plan, including GDPR's 72-hour breach notification.
  • Records of processing activities, and a data protection impact assessment where you process health data at scale.
  • A third-party penetration test — worth doing before you tell a hospital you are production-ready.
  • Who gets administrative access in the first place. We enforce least privilege in code; deciding who holds it is a process question.

What we do give you is the technical half, built so that an auditor asking "show me that a customer cannot reach another customer's records" gets a demonstration rather than an assurance.

Pricing

Priced by what you register, not who logs in.

You pay for the applications you register — each set of services with its own audience and permissions — not per user and not per tenant. A customer that grows from ten seats to ten thousand costs you the same; a second product line is what moves you up a plan.

Team
249 / mo
Up to 3 application sets

For a single product with a few backend services behind it.

  • Self-hosted, your infrastructure
  • All four SDKs and the full API
  • Email support, next business day
Start a trial
Scale
749 / mo
Up to 12 application sets

For a platform with several product lines, each its own set of services.

  • Everything in Team
  • Priority support with a response-time target
  • Upgrade guidance for major versions
Start a trial
Regulated
Let's talk
Unlimited application sets

For HIPAA or financial data, where isolation and paperwork are part of the product.

  • Signed BAA and DPA
  • Your own isolation level — a dedicated instance, or a database no other customer touches
  • The region and data residency you need
  • Contractual SLA and named contact
  • Onboarding and an architecture review
Talk to us

On Team and Scale you self-host: the price is the licence and support, not a hosting bill. An application set is one registered audience — a group of services that verify tokens together. Move between plans as you add or retire product lines. At the Regulated tier the price follows isolation — a dedicated instance, or a database for a single customer, costs more to run than a shared deployment, and that is the conversation to have.

Book a demo

Pick a slot. Talk to an engineer.

Choose a free time below and you get a working walkthrough — the isolation tests run live, the audit trail, the SDK dropped into a real service. Not a slide deck, and it starts on time.

Prefer email? Write to us and we'll find a time.

Bring us the customer whose structure broke your last system.

The four-level org chart, the shared email address across two legal entities, the auditor who wants to see refused access attempts. Those are the conversations we would rather have early.

Tell us what you are building. A real engineer reads every request and answers — usually within a day.

Email us directly