Theo Zourzouvillys

Blueprint 4stablev1.0.0

Authentication for a multi-tenant SaaS product

By
Theo Zourzouvillys
Published
Requirements
52 · ZBP-4-R1…R52
Tags
securitysaasauthidentityssomulti-tenancy

Pull this in

https://zrz.io/zbp/4-multi-tenant-saas-authentication/v1.md

Version-pinned. Latest tracks revisions; the pinned URL does not. Requirements are cited individually as ZBP-4-Rk, so an implementation can annotate and a review can check them one at a time.

Use when
You are building sign-in for a product where people belong to customer organisations, and one person may belong to several.
Not for
  • Service-to-service authentication — workloads should get tokens from an STS, not sign in.
  • Authorisation inside an organisation; this establishes who the caller is and which org they act in, not what they may do to a given record.
  • Consumer products with no organisation concept, where the org model is pure overhead.
Provides
saas-authenticationorganization-membershipsession-management

TL;DR

This specifies sign-in for a product where people belong to customer organisations. The shape of the answer: one global user account per person; membership in an organisation as an explicit, revocable record; a server-authoritative session that cannot outlive the membership it depends on; and an organisation’s security settings that bind every path into it, not just the front door.

The failure that matters here is not usually a broken password check. It is a side door: a session that survives an employee’s removal, an API key that belongs to a person who left, an invitation that grants more than the inviter had, a domain auto-join on a domain nobody verified, or a support tool that can enter any organisation without leaving a trace. This document is largely a specification of those doors.

It builds on ZBP-3Blueprint · v1.0.0ZBP-3 — Tenant isolation in a multi-tenant systemOne system stores or serves data belonging to more than one customer, and one customer seeing another's data would be a serious incident.Why it's cited here: The isolation boundary this document produces a tenant context for. Required, not optional: an authentication layer that resolves the right organisation is worth nothing if the data layer does not enforce it.Open ZBP-3 →, which enforces the boundary this establishes, and uses ZBP-1Blueprint · v1.0.0ZBP-1 — DPoP-bound requests across an API surfaceYou are issuing or accepting access tokens over HTTP and want a stolen token to be useless without the holder's private key.Why it's cited here: Sender-constrained credentials. Cited by ZBP-4-R46: where a client can hold a key, an organisation's API keys should be bound to it so a leaked key alone is not enough to use.Open ZBP-1 → for machine credentials.

Applicability

Use this when your product has customer organisations with more than one person in them, when one person may belong to more than one organisation, or when customers will eventually ask for SSO, directory sync, and audit — which they will, at the exact moment the deal is large enough to matter.

Do not use this when:

  • The caller is a workload, not a person. Services should not “sign in”. They attest and exchange for a short-lived token — ZBP-2Blueprint · v1.0.0ZBP-2 — A Security Token Service for workload identityServices in your platform need to authenticate to each other and you want every call attributable to a named workload holding no long-lived secret.Why it's cited here: The workload counterpart to this document, and a deliberate contrast: it makes verification a local computation because volume is enormous and lifetimes are minutes, where this makes the session store authoritative because immediate revocation matters more.Open ZBP-2 →.
  • You need authorisation, not authentication. This resolves who is calling and which organisation they are acting in. What they may then do to a specific record is a separate layer, and merging the two produces a permission model nobody can reason about.
  • There are no organisations. A consumer product where each account is one person does not need memberships, invitations, or SSO enforcement, and adding them costs real complexity.

Scope and non-goals

In scope: the user and organisation model; membership and its revocation; session establishment, resolution, and lifetime; credentials and multi-factor; federated sign-in and its enforcement; domain verification; directory-driven provisioning and deprovisioning; invitations; machine principals owned by an organisation; support and impersonation access; and audit.

Out of scope: intra-organisation authorisation and role design; the tenant isolation enforcement point (ZBP-3Blueprint · v1.0.0ZBP-3 — Tenant isolation in a multi-tenant systemOne system stores or serves data belonging to more than one customer, and one customer seeing another's data would be a serious incident.Why it's cited here: The isolation boundary this document produces a tenant context for. Required, not optional: an authentication layer that resolves the right organisation is worth nothing if the data layer does not enforce it.Open ZBP-3 →); workload identity (ZBP-2Blueprint · v1.0.0ZBP-2 — A Security Token Service for workload identityServices in your platform need to authenticate to each other and you want every call attributable to a named workload holding no long-lived secret.Why it's cited here: The workload counterpart to this document, and a deliberate contrast: it makes verification a local computation because volume is enormous and lifetimes are minutes, where this makes the session store authoritative because immediate revocation matters more.Open ZBP-2 →); billing and entitlements; and the specifics of any one identity provider’s implementation quirks.

Vocabulary

  • User — a person. Exactly one user record per person, globally, regardless of how many organisations they belong to.
  • Organisation — the tenant. The unit of isolation in ZBP-3Blueprint · v1.0.0ZBP-3 — Tenant isolation in a multi-tenant systemOne system stores or serves data belonging to more than one customer, and one customer seeing another's data would be a serious incident.Why it's cited here: The isolation boundary this document produces a tenant context for. Required, not optional: an authentication layer that resolves the right organisation is worth nothing if the data layer does not enforce it.Open ZBP-3 → and the unit of ownership here.
  • Membership — the explicit record joining a user to an organisation, carrying their roles and status within it. The authorisation-relevant object; a user alone is not.
  • Session — server-authoritative state representing an authenticated person on a device.
  • Session token — the opaque value the client presents, naming a session.
  • Active organisation — which of the caller’s memberships the current request is acting under.
  • Machine principal — a non-human identity owned by an organisation: an API key or service account.
  • Support access — a deliberate, audited path by which an operator of the product acts inside a customer organisation.
  • Identity provider (IdP) — the customer’s own directory, used for federated sign-in.

The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are to be interpreted as in RFC 2119 and RFC 8174.

Architecture

sign-in: password + MFA,or federated to the org IdPOIDC / SAML · SCIMcreatesper request:session user active orgmembershipyields tenant contextpersoncustomer IdPAUTHENTICATION user (global, one per person)sessionserver-authoritative, revocable inone placerecords user · auth method · MFA ·IdP · deviceMEMBERSHIP (user ×organisation)status · roles · sourcerevoked here everysession's access to that orgendsZBP-3 enforcement(tenant isolation)

Three structural choices carry the design:

  1. The membership is the authorisation object, not the user and not the session. A session says a person is who they claim. Only a live membership says they may act in this organisation, and it is checked on every request rather than baked into a token at sign-in. This is what makes removal actually remove.
  2. The session is server-authoritative. This is the opposite of the choice ZBP-2Blueprint · v1.0.0ZBP-2 — A Security Token Service for workload identityServices in your platform need to authenticate to each other and you want every call attributable to a named workload holding no long-lived secret.Why it's cited here: The workload counterpart to this document, and a deliberate contrast: it makes verification a local computation because volume is enormous and lifetimes are minutes, where this makes the session store authoritative because immediate revocation matters more.Open ZBP-2 → makes for workloads, deliberately. There, request volume is enormous and lifetimes are minutes, so verification must be a local computation. Here, volume is human-scale and sessions last days, so immediate revocation matters far more than saving a lookup. Same architect, opposite conclusion, because the forces genuinely differ — and a system that copies the workload answer into the human path ends up unable to log anyone out.
  3. Organisation security settings bind every path. SSO enforcement that closes the password form but leaves existing sessions, personal API keys, and recovery flows open has not enforced anything. Most of the requirements below are that idea applied to each door in turn.

Normative requirements

Users and organisations

  • ZBP-4-R1 A person MUST have exactly one user record, regardless of how many organisations they belong to. Per-organisation duplicate user records MUST NOT be created.
  • ZBP-4-R2 A user record MUST be able to exist with no organisation membership, and MUST remain addressable after losing all memberships, so that history and audit references stay resolvable.
  • ZBP-4-R3 Identifiers for users, organisations, memberships, and sessions MUST be opaque and non-enumerable, per ZBP-3-R1.
  • ZBP-4-R4 An email address MUST NOT by itself confer access to any organisation. It is a contactable identifier and a verification target, never an authorisation input.
  • ZBP-4-R5 Email addresses MUST be verified before use for sign-in, recovery, or invitation matching, and MUST be re-verified on change.
  • ZBP-4-R6 An organisation MUST have a security configuration — enforced sign-in methods, MFA requirement, session lifetime, allowed domains — that is owned by that organisation and MUST NOT be weakened by any individual member’s preference.
  • ZBP-4-R7 Deleting an organisation MUST NOT delete the user records of its members, and MUST revoke all memberships, sessions scoped to it, and machine principals owned by it.
  • ZBP-4-R8 The system MUST support one person holding memberships in multiple organisations simultaneously, including organisations with conflicting security configurations.

Membership and request context

  • ZBP-4-R9 Membership MUST be an explicit record with a status. Absence of a membership record MUST deny; there MUST NOT be an implicit membership derived from email domain, invitation, or history.
  • ZBP-4-R10 Every request MUST resolve, in order: session → user → active organisation → membership → roles. Failure at any step MUST deny.
  • ZBP-4-R11 Membership MUST be re-checked on every request against authoritative state. Roles and membership status MUST NOT be read solely from a token or cookie issued earlier.
  • ZBP-4-R12 Revoking a membership MUST take effect within a bounded, documented interval that MUST NOT exceed 60 seconds, across every surface including active sessions, in-flight background work, and cached authorisation decisions.
  • ZBP-4-R13 The active organisation MUST be resolved to a membership the session’s user actually holds. A client-supplied organisation identifier MUST be treated as a request to switch, validated against membership, and MUST NOT be trusted as context (ZBP-3-R3).
  • ZBP-4-R14 Switching the active organisation MUST re-evaluate that organisation’s security configuration, and MUST deny if the current session does not satisfy it — for example a password-authenticated session switching into an SSO-enforced organisation.
  • ZBP-4-R15 The last member able to administer an organisation MUST NOT be removable or demotable without an explicit ownership transfer, so that an organisation cannot be orphaned.

Sessions

  • ZBP-4-R16 A session MUST be server-authoritative: a record the server can revoke, whose revocation takes effect immediately for subsequent requests.
  • ZBP-4-R17 The session token MUST be opaque to the client, MUST carry at least 128 bits of entropy, and MUST be stored hashed at rest so that a database disclosure does not yield usable tokens.
  • ZBP-4-R18 A session MUST record how it was authenticated: the method, whether MFA was satisfied, the identity provider if federated, and the approximate device and client.
  • ZBP-4-R19 Sessions MUST have both an idle timeout and an absolute maximum lifetime, both configurable per organisation, with the strictest applicable value winning for a user with several memberships.
  • ZBP-4-R20 The session token MUST be rotated on privilege change — sign-in, MFA completion, step-up, and password change — and the previous value MUST be invalidated.
  • ZBP-4-R21 Browser-delivered session tokens MUST be set HttpOnly, Secure, and SameSite=Lax or stricter, and state-changing requests MUST be protected against cross-site request forgery independently of the cookie.
  • ZBP-4-R22 A user MUST be able to enumerate their active sessions and revoke any or all of them, and an organisation administrator MUST be able to revoke that organisation’s members’ sessions.
  • ZBP-4-R23 Changing a credential — password, MFA factor, or recovery method — MUST revoke all other sessions for that user by default.
  • ZBP-4-R24 A session MUST NOT grant access to an organisation whose membership has been revoked, even if the session itself remains valid for other organisations.

Credentials and multi-factor

  • ZBP-4-R25 Passwords, where supported, MUST be stored with a memory-hard hash with per-credential salt, MUST be checked against a breached-password corpus at set time, and MUST NOT be subject to composition rules that reduce entropy.
  • ZBP-4-R26 Phishing-resistant factors — passkeys and hardware authenticators — MUST be supported, and an organisation MUST be able to require them.
  • ZBP-4-R27 Where an organisation requires MFA, that requirement MUST apply to every authentication path into it, including federated sign-in, recovery, and machine principal creation.
  • ZBP-4-R28 Sensitive operations — changing security configuration, managing machine principals, transferring ownership, exporting data — MUST require step-up re-authentication within a short, bounded recency window.
  • ZBP-4-R29 Account recovery MUST NOT bypass an organisation’s enforced sign-in method or MFA requirement. Recovery restores access to the user; it MUST NOT restore access to an SSO-enforced organisation without the identity provider.
  • ZBP-4-R30 Authentication responses MUST NOT reveal whether an account exists, and rate limiting MUST apply per account and per source independently.

Federated sign-in and provisioning

  • ZBP-4-R31 A domain MUST be verified by a control proof — a DNS record or a document served from the domain — before it may be associated with an organisation. Unverified domains MUST NOT influence any routing or joining decision.
  • ZBP-4-R32 Domain-based automatic joining, where offered, MUST require a verified domain, MUST be explicitly enabled by an organisation administrator, and MUST be recorded on each membership it creates.
  • ZBP-4-R33 A verified domain MUST NOT be claimable by a second organisation while the claim is active, and a public email provider’s domain MUST NOT be claimable at all.
  • ZBP-4-R34 Federated assertions MUST be validated against the organisation’s configured provider: signature, issuer, audience, recency, and single use of the assertion identifier. The organisation MUST be determined by the connection the assertion arrived on, never by a claim inside it.
  • ZBP-4-R35 When an organisation enforces SSO, every other path into that organisation MUST be closed for its members: password sign-in, existing non-SSO sessions, and personal machine principals. Enabling enforcement MUST invalidate sessions that do not satisfy it.
  • ZBP-4-R36 Directory-driven deprovisioning MUST revoke the membership, its sessions, and its machine principals within the interval in ZBP-4-R12.
  • ZBP-4-R37 Directory-driven provisioning MUST NOT grant administrative roles unless the mapping from directory group to role is explicitly configured by an organisation administrator.
  • ZBP-4-R38 Loss of connectivity to a customer’s identity provider MUST fail closed for new sessions, and MUST NOT silently fall back to password authentication. A documented break-glass path MAY exist; it MUST be time-bounded and audited.

Invitations

  • ZBP-4-R39 An invitation MUST be single-use, MUST expire, MUST be bound to a specific email address, and MUST be redeemable only by a user who has verified that address.
  • ZBP-4-R40 An invitation MUST NOT grant roles exceeding those the inviter holds and is permitted to delegate, and the granted roles MUST be re-validated at redemption, not only at issue.
  • ZBP-4-R41 Invitation tokens MUST be integrity-protected such that no field — organisation, email, or roles — can be modified without detection, and MUST be revocable before redemption.
  • ZBP-4-R42 Redeeming an invitation MUST create an explicit membership record and MUST be audited with the inviter, redeemer, roles, and time.

Machine principals within an organisation

  • ZBP-4-R43 A machine principal MUST be owned by the organisation, not by the person who created it, and MUST survive that person’s departure without granting continued access to that person.
  • ZBP-4-R44 A machine principal MUST have a named human owner for accountability, an expiry, and scopes narrower than or equal to the creating member’s authority at creation time.
  • ZBP-4-R45 Machine principal credentials MUST be shown once, stored hashed, and MUST be individually revocable. Their use MUST be attributable in audit to the principal, per ZFN-40Field Note · currentZFN-40 — No anonymous "system" actorIf "system" appears as an actor in your audit log, attribution is already broken. Every automated action — cron job, cleanup task, migration, agent — runs as a named identity with its own credentials and scope, so "who did this?" has an answer and revocation is surgical.Why it's cited here: Why a machine principal has a named accountable owner and why its use is attributable in audit.Open ZFN-40 →.
  • ZBP-4-R46 Where the client can hold a key, machine principal credentials SHOULD be sender-constrained per ZBP-1Blueprint · v1.0.0ZBP-1 — DPoP-bound requests across an API surfaceYou are issuing or accepting access tokens over HTTP and want a stolen token to be useless without the holder's private key.Why it's cited here: Sender-constrained credentials. Cited by ZBP-4-R46: where a client can hold a key, an organisation's API keys should be bound to it so a leaked key alone is not enough to use.Open ZBP-1 →, so that a leaked key is not sufficient to use it.

Support access and impersonation

  • ZBP-4-R47 Product operators MUST NOT hold standing access to customer organisations. Access MUST be requested per incident, time-bounded, and expire automatically.
  • ZBP-4-R48 Support access MUST be recorded as the operator acting for the organisation, with both identities present — never by assuming a customer user’s identity such that the audit trail shows the customer performing the action.
  • ZBP-4-R49 Support access MUST be visible to the customer: surfaced in their own audit log, and where the organisation requires it, gated on explicit customer approval.
  • ZBP-4-R50 Support sessions MUST be read-only by default; write access MUST be a separate, explicitly elevated grant with its own justification and approval.

Audit

  • ZBP-4-R51 Authentication events — sign-in, failure, MFA, session revocation, membership change, role change, invitation, machine principal lifecycle, support access — MUST be recorded with actor, organisation, method, source, and outcome.
  • ZBP-4-R52 Each organisation MUST be able to read its own audit records, and those records MUST NOT contain another organisation’s data (ZBP-3-R26).

Data model

The identity core — a person, the organisations they belong to, and the sessions they hold:

holdsgrantsauthenticates asUSERMEMBERSHIPstringstatusstringrolesstringsourceinvite|sso|domainORGANISATIONSESSIONstringtoken_hashhashed at reststringauth_methodpassword|passkey|ssoboolmfa_satisfiedstringexpires_atidle + absolute

What an organisation owns — the settings and principals that belong to the tenant rather than to any person in it:

configuresclaimsownsORGANISATIONSECURITY_CONFIGboolenforced_ssoboolrequire_mfaintsession_idleintsession_maxVERIFIED_DOMAINstringproofstringverified_atMACHINE_PRINCIPALstringowner_useraccountable humanstringexpires_atstringscopes

membership.source is not bookkeeping. When an organisation turns on SSO enforcement (ZBP-4-R35) or a directory removes a user (ZBP-4-R36), it is how you determine which memberships and sessions are affected. Without it, enforcement becomes a guess.

Note what the session record does not contain: roles, or the organisation’s permissions. Those are resolved per request from membership (ZBP-4-R11), which is what makes ZBP-4-R12 achievable at all.

Request resolution algorithm

Every authenticated request, in this order:

#StepRequirementFailure
1Session token present and well-formedZBP-4-R17401
2Session found by token hash, not expired, not revokedZBP-4-R16401
3Idle and absolute lifetimes satisfiedZBP-4-R19401
4User resolved and not disabledZBP-4-R1401
5Active organisation resolved from session state, or from a validated switchZBP-4-R13403
6Membership found for (user, organisation) and status is activeZBP-4-R9, ZBP-4-R10403
7Organisation security config satisfied by this sessionZBP-4-R14, ZBP-4-R35403 or re-auth
8Roles loaded from the membership record, not from the sessionZBP-4-R11403
9Step-up recency satisfied, if the operation requires itZBP-4-R28403 + step-up
10Tenant context established and handed to the ZBP-3Blueprint · v1.0.0ZBP-3 — Tenant isolation in a multi-tenant systemOne system stores or serves data belonging to more than one customer, and one customer seeing another's data would be a serious incident.Why it's cited here: The isolation boundary this document produces a tenant context for. Required, not optional: an authentication layer that resolves the right organisation is worth nothing if the data layer does not enforce it.Open ZBP-3 → enforcement pointZBP-3-R2deny

Step 6 before step 8, always. Reading roles from anywhere but the live membership record is what produces the class of bug where a removed administrator keeps administering until their session happens to expire.

Step 7 is the one most often missing entirely. A session created before an organisation enabled SSO enforcement satisfies steps 1–6 perfectly well; only an explicit re-evaluation against the current configuration closes it.

Test vectors

Invitation token

An invitation is verified only by its issuer, so a MAC is the right primitive — no public verification is needed and a symmetric key is simpler to rotate. This is a published test key and MUST NOT be used for anything real.

key (base64url, HMAC-SHA256): ZmllbGQtbm90ZXMtdGVzdC1pbnZpdGF0aW9uLWtleS12MQ
token form:  inv_<base64url(payload)>.<base64url(HMAC-SHA256(key, base64url(payload)))>

Payload:

{
  "v": 1,
  "jti": "01JZQ9M4T7C2X8B5N0KWERZDAH",
  "org": "org_7Fq2mKdX9pLs",
  "email": "sam@customer.example",
  "roles": ["member"],
  "inviter": "usr_3Bn8vQwR1tYc",
  "iat": 1782000000,
  "exp": 1782604800
}

V-INV1 — valid (expect: accept, then be unusable a second time). Verified as authentic.

inv_eyJ2IjoxLCJqdGkiOiIwMUpaUTlNNFQ3QzJYOEI1TjBLV0VSWkRBSCIsIm9yZyI6Im9yZ183RnEybUtkWDlwTHMiLCJlbWFpbCI6InNhbUBjdXN0b21lci5leGFtcGxlIiwicm9sZXMiOlsibWVtYmVyIl0sImludml0ZXIiOiJ1c3JfM0JuOHZRd1IxdFljIiwiaWF0IjoxNzgyMDAwMDAwLCJleHAiOjE3ODI2MDQ4MDB9.AlSWIH5poAajFLD5xxXM2DOHZPL0jjdzdhfqDVgGk6g

V-INV2 — role escalation attempt (expect: reject on integrity). Identical payload except "roles": ["owner"], presented with V-INV1’s unmodified MAC. The MAC over the modified body is bco2emM9xW85E8_ETEKveob6mXGZpNNJ77JkGkUp0ZM; the token presents AlSWIH5poAajFLD5xxXM2DOHZPL0jjdzdhfqDVgGk6g. Tests ZBP-4-R41.

inv_eyJ2IjoxLCJqdGkiOiIwMUpaUTlNNFQ3QzJYOEI1TjBLV0VSWkRBSCIsIm9yZyI6Im9yZ183RnEybUtkWDlwTHMiLCJlbWFpbCI6InNhbUBjdXN0b21lci5leGFtcGxlIiwicm9sZXMiOlsib3duZXIiXSwiaW52aXRlciI6InVzcl8zQm44dlF3UjF0WWMiLCJpYXQiOjE3ODIwMDAwMDAsImV4cCI6MTc4MjYwNDgwMH0.AlSWIH5poAajFLD5xxXM2DOHZPL0jjdzdhfqDVgGk6g

Note that integrity protection alone is not sufficient: even a correctly-MAC’d invitation must have its roles re-validated against the inviter’s current authority at redemption (ZBP-4-R40), because the inviter may have been demoted in the seven days since.

Decision matrix

The rest of this specification’s behaviour is state-dependent rather than cryptographic, and is verified as a decision table. A conforming implementation MUST produce these outcomes. Each row is a test.

#SituationRequired outcomeRequirement
A1Valid session, active membershipallowZBP-4-R10
A2Valid session, membership revoked 60s agodenyZBP-4-R12, ZBP-4-R24
A3Valid session, membership revoked in org X, active in org Ydeny for X, allow for YZBP-4-R24
A4Session’s cached roles say admin; membership says membertreat as memberZBP-4-R11
A5Request names an org the user has no membership indeny, indistinguishable from a non-existent orgZBP-4-R13, ZBP-3-R20
A6Password session, org later enabled SSO enforcementdeny / force re-authZBP-4-R14, ZBP-4-R35
A7Org requires MFA; session authenticated without itdeny, step upZBP-4-R27
A8User recovers account by email; org enforces SSOuser restored, org access still deniedZBP-4-R29
A9Sign-in attempt for a non-existent accountsame response and timing as a wrong passwordZBP-4-R30
B1Invitation redeemed by a different email addressdenyZBP-4-R39
B2Invitation redeemed twicesecond redemption deniedZBP-4-R39
B3Invitation granting owner, issued by a memberdeny at issue and at redemptionZBP-4-R40
B4Invitation valid, but inviter demoted before redemptionre-validate; deny the excess rolesZBP-4-R40
C1Auto-join on an unverified domaindenyZBP-4-R31, ZBP-4-R32
C2Second org claims an already-verified domaindenyZBP-4-R33
C3Auto-join on a public email provider domaindenyZBP-4-R33
C4SSO assertion naming an org other than the connection’suse the connection’s org; deny the claimZBP-4-R34
C5SSO assertion replayeddeny on assertion id single-useZBP-4-R34
C6Customer IdP unreachablenew sessions fail closed; no password fallbackZBP-4-R38
C7SCIM deprovision receivedmembership, sessions, machine principals revoked ≤60sZBP-4-R36
D1API key created by a user who has since leftkey still valid; that person has no accessZBP-4-R43
D2API key scope exceeding its creator’s authoritydeny at creationZBP-4-R44
D3Org enables SSO enforcement; personal API keys existpersonal keys closed; org-owned principals surviveZBP-4-R35, ZBP-4-R43
E1Operator accesses an org without a time-bound grantdenyZBP-4-R47
E2Operator acts in an orgaudit shows operator and org, not the customer as actorZBP-4-R48
E3Support access occursvisible in the customer’s own audit logZBP-4-R49
E4Operator writes during a read-only support sessiondenyZBP-4-R50

A2, A6, and D1 are the three that most often fail in a real implementation, and they fail silently — nothing errors, the wrong person simply keeps working. A6 in particular cannot be caught by testing a fresh sign-in, because the defect only exists for sessions that predate the configuration change.

Threat model and failure modes

ThreatResult
Employee removed from a customer, keeps their sessionMembership re-checked per request; bounded revocation (ZBP-4-R11, ZBP-4-R12)
Employee removed, keeps a personal API keyMachine principals are org-owned and revoked with the membership (ZBP-4-R36, ZBP-4-R43)
Attacker registers an email at a customer’s domainDomain claims require a control proof (ZBP-4-R31)
Attacker claims a customer’s domain in their own orgDomains are exclusive while claimed (ZBP-4-R33)
SSO assertion replayed or retargetedSingle-use assertion id; org from the connection (ZBP-4-R34)
Org enables SSO; attacker uses a pre-existing password sessionEnforcement invalidates non-satisfying sessions (ZBP-4-R35)
Attacker uses account recovery to bypass SSORecovery restores the user, not the org (ZBP-4-R29)
Invitation tampered to grant ownerIntegrity-protected and re-validated (V-INV2, ZBP-4-R40, ZBP-4-R41)
Session database disclosedTokens stored hashed; disclosure yields nothing usable (ZBP-4-R17)
Product operator browses customer dataNo standing access; time-bound, audited, customer-visible (ZBP-4-R47…R49)
Cross-organisation data access through a valid sessionContext handed to ZBP-3Blueprint · v1.0.0ZBP-3 — Tenant isolation in a multi-tenant systemOne system stores or serves data belonging to more than one customer, and one customer seeing another's data would be a serious incident.Why it's cited here: The isolation boundary this document produces a tenant context for. Required, not optional: an authentication layer that resolves the right organisation is worth nothing if the data layer does not enforce it.Open ZBP-3 →’s enforcement point (ZBP-3-R9)
Customer’s IdP compromisedTheir org is compromised. This is inherent to federation and must be stated to customers, not engineered away
Product’s own session store compromisedTotal. Concentrating session authority is what buys instant revocation; it also concentrates this risk

The last two rows are the honest limits. Federation delegates trust to the customer’s directory — that is what they are asking for. And a server-authoritative session store is a single high-value target, which is the price of being able to end every session in the platform in one operation. Both are the right trades for this problem; neither should be discovered during an incident review.

Anti-patterns

  • Baking roles into the session. Produces the removed-administrator bug, which is invisible until it matters (ZBP-4-R11).
  • A user record per organisation. Breaks single sign-on, MFA enrolment, and account recovery, and makes “this person is at two customers” unrepresentable. It also multiplies the credential surface by the number of organisations (ZBP-4-R1).
  • Trusting the organisation id in the request. It is a switch request to validate, not context (ZBP-4-R13, ZBP-3-R3).
  • SSO enforcement that only closes the login form. Existing sessions, personal API keys, and recovery are the doors that matter (ZBP-4-R35).
  • Auto-join by email domain without verification. Register a mailbox, join the organisation. The most direct tenancy takeover there is (ZBP-4-R31).
  • Personal API keys. They leave with the person, or worse, do not (ZBP-4-R43).
  • Impersonation implemented as “log in as this user”. The audit trail then shows the customer performing the operator’s actions, which is worse than no audit trail, because it is confidently wrong (ZBP-4-R48).
  • Standing operator access to all organisations. One phished employee at the vendor is every customer’s breach (ZBP-4-R47).
  • Recovery that bypasses org policy. The recovery flow becomes the weakest sign-in method, and it is the one nobody threat-models (ZBP-4-R29).
  • Falling back to passwords when the customer’s IdP is down. Turns their outage into your breach (ZBP-4-R38).

Rollout

Adding organisations to a product that has only users:

  1. Introduce organisation and membership records, backfilling one organisation per existing user. Nothing changes behaviourally; every user is a sole member of their own organisation.
  2. Move authorisation reads onto membership (ZBP-4-R11). Still one membership each, so still no behaviour change — but now the resolution path is correct.
  3. Add the active-organisation concept and switching (ZBP-4-R13), with a real multi-membership test account.
  4. Add invitations (ZBP-4-R39…R42). This is when organisations become genuinely multi-person and when role delegation first matters.
  5. Add the organisation security configuration (ZBP-4-R6) with defaults matching current behaviour, so enabling it is a customer choice rather than a migration.
  6. Add federation, then enforcement — in that order, and treat them as separate launches. Enforcement is the one that breaks people, because it must invalidate existing sessions (ZBP-4-R35).
  7. Add directory provisioning (ZBP-4-R36, ZBP-4-R37). Deprovisioning is the part customers actually audit; build it first and demonstrate the revocation interval.
  8. Replace operator access with the audited, time-bound path (ZBP-4-R47…R50). Do this before you need it in a customer security review, not during one.

Step 6 is the schedule risk. Every prior step is additive; enforcement is the first one that takes access away from people who currently have it, and it needs a communicated window.

Conformance checklist

Model

  • One user record per person (ZBP-4-R1)
  • Users survive with zero memberships (ZBP-4-R2)
  • All identifiers opaque and non-enumerable (ZBP-4-R3)
  • Email confers no access by itself (ZBP-4-R4)
  • Email verified before use and re-verified on change (ZBP-4-R5)
  • Org-owned security configuration, not weakenable by members (ZBP-4-R6)
  • Org deletion revokes memberships, sessions, principals; keeps users (ZBP-4-R7)
  • Multi-org membership with conflicting configs supported (ZBP-4-R8)

Membership and resolution

  • Membership explicit; absence denies (ZBP-4-R9)
  • Full resolution chain on every request (ZBP-4-R10)
  • Roles and status read live, never from the token (ZBP-4-R11)
  • Revocation effective ≤60s across every surface (ZBP-4-R12)
  • Org switch validated against membership (ZBP-4-R13)
  • Security config re-evaluated on switch (ZBP-4-R14)
  • Last administrator cannot be removed without transfer (ZBP-4-R15)

Sessions

  • Server-authoritative and immediately revocable (ZBP-4-R16)
  • Opaque, ≥128 bits, stored hashed (ZBP-4-R17)
  • Authentication method, MFA state, IdP, device recorded (ZBP-4-R18)
  • Idle and absolute lifetimes, strictest-wins across orgs (ZBP-4-R19)
  • Rotated on every privilege change (ZBP-4-R20)
  • Cookie flags set; CSRF defence independent of the cookie (ZBP-4-R21)
  • Users and admins can enumerate and revoke sessions (ZBP-4-R22)
  • Credential change revokes other sessions (ZBP-4-R23)
  • Session grants nothing in a revoked org (ZBP-4-R24)

Credentials

  • Memory-hard hashing, breach-corpus check, no composition rules (ZBP-4-R25)
  • Phishing-resistant factors supported and requirable (ZBP-4-R26)
  • MFA requirement applies to every path in (ZBP-4-R27)
  • Step-up on sensitive operations (ZBP-4-R28)
  • Recovery cannot bypass org enforcement (ZBP-4-R29)
  • No account enumeration; per-account and per-source rate limits (ZBP-4-R30)

Federation

  • Domain control proof required before any effect (ZBP-4-R31)
  • Auto-join requires verified domain and explicit enablement (ZBP-4-R32)
  • Domains exclusive; public providers unclaimable (ZBP-4-R33)
  • Assertions fully validated; org from the connection (ZBP-4-R34)
  • Enforcement closes every other path and invalidates sessions (ZBP-4-R35)
  • Deprovisioning revokes membership, sessions, principals (ZBP-4-R36)
  • Directory-driven admin roles require explicit mapping (ZBP-4-R37)
  • IdP outage fails closed; break-glass bounded and audited (ZBP-4-R38)

Invitations

  • Single-use, expiring, email-bound, verified-address redemption (ZBP-4-R39)
  • Roles bounded by inviter and re-validated at redemption (ZBP-4-R40)
  • Integrity-protected and revocable (ZBP-4-R41)
  • Redemption creates an explicit membership and is audited (ZBP-4-R42)

Machine principals

  • Owned by the org, surviving their creator’s departure (ZBP-4-R43)
  • Named human owner, expiry, bounded scopes (ZBP-4-R44)
  • Shown once, stored hashed, individually revocable, attributable (ZBP-4-R45)
  • Sender-constrained where the client can hold a key (ZBP-4-R46)

Support access

  • No standing access; per-incident and expiring (ZBP-4-R47)
  • Both identities in the audit record (ZBP-4-R48)
  • Customer-visible, approvable where required (ZBP-4-R49)
  • Read-only by default; writes separately elevated (ZBP-4-R50)

Audit

  • All authentication events recorded with full context (ZBP-4-R51)
  • Orgs read their own records; no cross-org content (ZBP-4-R52)

Test suite

  • V-INV1 and V-INV2 verify as stated
  • Every row of the decision matrix is a test
  • A2, A6, and D1 asserted explicitly — the three silent failures
  • Revocation interval measured, not assumed (ZBP-4-R12)

Rationale

Not speaking for people who have not consented is ZFN-8Field Note · currentZFN-8 — Don't hide behind anonymous 'people'Never invoke unnamed 'people' to carry weight — 'a few people are concerned', 'some think'. It launders one view as phantom consensus and makes the listener argue a crowd they can't see. Name them and bring them in, or own it. If they can't speak up, fix the culture.Why it's cited here: The root of the impersonation position here: support access is recorded as the operator acting for the organisation, never as the customer performing the action.Open ZFN-8 →, which is the root of the impersonation position here. That an agent — or an operator — acting with someone else’s credential is untraceable by design, and that delegation must be explicit, scoped, and revocable, is ZFN-38Field Note · currentZFN-38 — Agents are principals: delegate, never impersonateAn agent acting with a copied user credential is impersonation — untraceable by design. Give agents their own identities and keys; let them act for a human only through explicit, scoped, time-bounded, revocable delegation; and record both actor and principal on every action.Why it's cited here: Directly behind the delegation model and the requirement that both actor and principal appear on every action.Open ZFN-38 →; that no automated actor is anonymous is ZFN-40Field Note · currentZFN-40 — No anonymous "system" actorIf "system" appears as an actor in your audit log, attribution is already broken. Every automated action — cron job, cleanup task, migration, agent — runs as a named identity with its own credentials and scope, so "who did this?" has an answer and revocation is surgical.Why it's cited here: Why a machine principal has a named accountable owner and why its use is attributable in audit.Open ZFN-40 →. Verifying that a resource belongs to the caller rather than inferring it from possession of an identifier is ZFN-10Field Note · currentZFN-10 — Pin the expected owner on cross-account resource calls (confused-deputy defense)Authority to call a resource isn't proof it's the one you meant. Any call crossing an account boundary must assert the expected owner: ExpectedBucketOwner on S3, aws:ResourceAccount conditions, validation of untrusted ARNs, plus inbound trust pinned with SourceArn/ExternalId.Why it's cited here: Applied here to the organisation named in a request, which is a switch to validate rather than context to trust.Open ZFN-10 →. Sessions and support grants as leases that expire rather than standing rights is ZFN-37Field Note · currentZFN-37 — Every lock is a leaseA lock that can outlive its holder is a deadlock scheduled for later. Give every lock — including informal ones like claimed_by columns — a TTL, a named owner, and a heartbeat; make expiry automatic and server-side; fence the side effects so a stale holder can't corrupt anything.Why it's cited here: Why sessions carry both idle and absolute lifetimes, and why support grants expire automatically instead of being cleaned up later.Open ZFN-37 →. And the standard for who gets to be inside a system at all — including your own operators — is ZFN-27Field Note · currentZFN-27 — Don't tolerate assholes — but be strict about what one isDon't tolerate assholes — people who demean, belittle, punch down. But filter hard on the word: disagreeing, raising ideas, or opening a competing PR isn't being an asshole, it's the work. Assholes attack people; colleagues attack problems. Don't let the label silence dissent.Why it's cited here: The standard for who gets to be inside a system at all, applied to access rather than hiring — the framing behind treating operator access as conditional and revocable rather than standing.Open ZFN-27 → applied to access rather than hiring: the privilege is conditional.

Two positions are specific to this document.

The membership is the object. Almost every serious bug in SaaS authentication comes from treating the user or the session as the authorisation subject and then discovering that organisations revoke, suspend, and reconfigure independently of either. Making membership the thing that is checked, live, on every request, costs a lookup and removes an entire category.

Sessions here are deliberately the opposite of workload tokens. ZBP-2Blueprint · v1.0.0ZBP-2 — A Security Token Service for workload identityServices in your platform need to authenticate to each other and you want every call attributable to a named workload holding no long-lived secret.Why it's cited here: The workload counterpart to this document, and a deliberate contrast: it makes verification a local computation because volume is enormous and lifetimes are minutes, where this makes the session store authoritative because immediate revocation matters more.Open ZBP-2 → says verification must be a local computation and revocation is a rare, secondary path. This document says the session store is authoritative and revocation is immediate. Both are correct for their traffic: one is millions of five-minute credentials where a lookup per request would be architecturally fatal; the other is human-scale, multi-day sessions where “log this person out now” is a routine, contractual requirement. The mistake is not choosing either — it is choosing one and applying it to both.

Changelog

  • 2026-07-27 (1.0.0): First published. Specifies the user/organisation/membership model, the ten-step request resolution algorithm, server-authoritative sessions, credentials and step-up, domain verification and SSO enforcement, directory provisioning, invitations, org-owned machine principals, audited support access, and vectors V-INV1/V-INV2 plus the A/B/C/D/E decision matrix.