ENFR
Authorisation and access

One place decides what each person may see

An organisation, its spaces, its roles, its named permissions and its API keys should not be governed in five different places. Missivia composes them into a single authorisation, computed on every call, server-side — whatever the client calling, web console, script or integration.

Entities, spaces and memberships

A space is a data perimeter, not a tab: what it holds is visible from no other one.

An organisation holds spaces — one per data perimeter: a brand, a subsidiary, an environment. A person reaches a space through a membership, which carries their role in that space: the same person may be an editor here and a plain viewer elsewhere.

The space concerned by a call is never supplied by the caller: it is derived from the authentication token, and every database query goes through an access layer that enforces it. A resource belonging to another space is not found, not forbidden — and every resource type has an automated isolation test, run on every integration.

What a space holds of its own
  • Its contacts, lists, segments and consent register.
  • Its templates, fragments, files and public pages.
  • Its journeys, campaigns and service messages.
  • Its sending domains, sending quotas and bounce thresholds.
  • Its retention periods, API keys and webhook subscriptions.

How an authorisation is computed

Five elements, in that order, on every call. Nothing is decided by the interface making it.

  1. 1

    Space

    The call is bound to a space, derived from the token. It cannot name another one.

  2. 2

    Role

    The membership brings a role, that is, a set of capabilities inherited as a whole — not a checkbox per screen.

  3. 3

    Named permissions

    They add to the role, one at a time, and are granted to a designated person: access to sensitive fields is one of them.

  4. 4

    Key class

    Every API key carries a class that caps the whole: what it cannot reach, no role gives back to it.

  5. 5

    Decision

    A single matrix decides, server-side, and writes its decision to the audit log — refusals included.

Rights that are inherited, cumulative and capped

  • Inherited. A role is a coherent set of capabilities, not a list of exceptions. You change the role of a membership; you do not revisit thirty checkboxes.
  • Cumulative. A named permission — access to sensitive fields, for instance — adds to the role without replacing it. It is granted and withdrawn separately, and its grant is dated and logged.
  • Capped. The class of the API key bounds the result. A key meant for technical operations does not reach a contact record, even carrying a role that would allow it: the capability is stored, it is simply never exercised. Creating a key with a capability outside its class is refused, with the list of rejected capabilities.
  • Verifiable. One dedicated call returns what the key can effectively do: the intersection of what it carries and what its class allows.
  • Technical / data separation. Platform operation roles run the series and administer the technical side; none of them reads a record, a nominative event, a message or a nominative export.
  • No impersonation. A platform role cannot borrow a customer user’s account, nor “view as” them.
  • Indistinguishable refusals. An access that is not granted answers “not found”, never “forbidden”: the existence of an access to people is not observable from outside.
  • Every access is logged, and a per-data-subject export returns everything that was done to that person, by whom and when.
Why an interface must ask what it may do

A console that builds its navigation on the capabilities requested when a key was created shows screens that will answer “not found”. Missivia therefore exposes the effective authorisation — the intersection of the key’s capabilities and its class ceiling — and navigation is built on that answer. What the screen offers is what the server will grant.

The same principle applies to the human actor: actions taken from an administration interface are attached to the person who triggered them, through a signed header, in addition to the key used. That header grants no right; it names, it does not authorise.

The matrix, in plain words

What each role reaches, written once and enforced everywhere.

What each role reaches. “Read” means consultation without modification; “—” means the operation does not exist for that role. The first three columns are customer roles, the data controller; the last two are platform operation roles.
What is requested Data administrator Editor Viewer Operations Technical administration
Records, histories, nominative exportsYesYesRead
Sensitive fields of a recordOn a named permission, and logged
Consents and data-subject rightsYesYesRead
Lists, segments, journeys, campaignsYesYesReadYes
Templates, files, public pages, webhooksYesYesReadYesYes
StatisticsExact valuesExact valuesExact valuesAggregates, masked below thresholdAggregates, masked below threshold
Retention periods, full export, permanent deletionYes
Keys, domains, integrations, job healthYesYes
Audit logWith identitiesWith identitiesWith identitiesWithout identitiesWithout identities

The restriction is published in the API contract, operation by operation: it can be read before it is tested, and an automated check fails if an operation serving personal data is added without being covered.

How to read this matrix
  • “Read” means consultation without modification.
  • “—” means the operation does not exist for that role: the call answers “not found”.
  • The first three columns are customer roles, the data controller; the last two are platform operation roles.
  • “Aggregates, masked below threshold”: a counter covering fewer than twenty people is masked, and so are the rates that could be derived from it. A small cohort points back to individuals.
  • A named permission never moves a column: it opens a row, for a designated person, and every read it allows is logged.

Users, keys and sessions

Two ways in — an authenticated person, or an API key — and a single way to be authorised.

  • Two-factor authentication for everyone, with no exception by role; single sign-on through the customer’s identity provider is available.
  • An API key carries explicit capabilities, a class, and nothing implicit: the secret is never returned after creation, revocation is immediate.
  • Restriction by IP address or range is available, together with rate limiting of authentication failures per origin.
  • Test keys and production keys are distinct and visibly prefixed; a test key sends nothing to the outside world.
  • Every key creation, change and revocation is written to the audit log, with the human actor when there is one.
Least privilege, in practice
  • An integration that only ingests contacts gets contact writes, nothing else: no templates, no exports, no statistics.
  • A technical operations key administers domains, quotas and job health; it reads no record, no message, no nominative export.
  • A key meant to run sends drives lists, journeys and campaigns, and only ever sees aggregate statistics, masked below the threshold.
  • A capability requested outside the key’s class is not silently ignored: creation is refused, and the answer names the rejected capabilities.