All identities, workflows and operating rules below are hypothetical or proposed. The active organisation is a workflow scope, not proof of authorisation; the backend must verify current membership and the requested operation.
Understanding the Challenge of Multi-Organisation Users
In SaaS products serving multiple organisations, users often belong to more than one organisation. Allowing these users to operate across organisations without mixing data is critical for security, compliance, and user trust. The main challenge is ensuring that data access and actions are strictly scoped to the currently active organisation, preventing accidental or malicious cross-organisation data leaks.
Enforcing an Explicit Active Organisation Context
The foundation of safe multi-organisation user interaction is requiring an explicit "active organisation" context. Every read, write, or export operation must be associated with this active organisation. This means the application should never infer or default to an organisation without explicit selection or confirmation by the user.
Practical steps:
- On login or session start, prompt the user to select the active organisation if multiple are available.
- Store the active organisation context securely in the session or JWT claims.
- Include the active organisation ID in every API request and database query.
Visible Active Organisation Context in the User Interface
Users must always be aware of which organisation they are working in to avoid confusion and errors. The UI should prominently display the active organisation, for example in the header or navigation bar.
UI considerations:
- Use clear labels with organisation names and logos.
- Provide a dropdown or switcher control to change the active organisation.
- Disable or warn when no organisation is selected.
Backend Data Isolation and Access Control
Backend systems must enforce data isolation by organisation using access control policies. This prevents data leakage even if frontend controls fail.
Recommended approach:
- Implement row-level security (RLS) in the database to filter data by organisation ID.
- Validate the active organisation context against user permissions on every request.
- Reject requests that attempt to access data outside the active organisation.
Handling Organisation Switching Mid-Task
Users may need to switch organisations during a session or even mid-task. This requires careful handling to avoid data corruption or confusion.
Best practices:
- Confirm any unsaved changes before switching organisations.
- Clear or reset context-sensitive data caches and forms.
- Reload data scoped to the newly active organisation.
- Provide clear feedback about the switch.
Testing Multi-Organisation User Flows
Robust automated and manual tests are essential to verify that organisation scoping works correctly.
Test scenarios:
- Accessing data with different active organisations.
- Switching organisations mid-task with and without unsaved changes.
- Attempting unauthorized access to other organisations' data.
- Exporting data scoped to the active organisation.
Multi-Organisation Interaction Contract: A Practical Template
Below is a proposed interaction contract template that SaaS teams can adapt and implement to govern multi-organisation user behaviour.
| Event/State | Description | Expected Behaviour | Validation/Test Criteria |
|---|---|---|---|
| User Login | User logs in with multiple organisation memberships | Prompt user to select active organisation if more than one exists | Active organisation selected and stored in session |
| Active Organisation Set | User selects or confirms active organisation | Active organisation context is applied to all subsequent requests | API requests include organisation ID; data filtered accordingly |
| Data Read/Write/Export | User performs CRUD or export operations | Operations only affect data belonging to active organisation | Database queries scoped; exports contain only active org data |
| Organisation Switch Initiated | User requests to switch active organisation mid-task | Confirm unsaved changes; warn user if needed | Confirmation dialog shown; unsaved changes handled |
| Organisation Switch Completed | Active organisation context updated | UI updates to reflect new organisation; data reloads accordingly | UI shows new org; data matches new org; no data leakage |
| Unauthorized Access Attempt | User tries to access data outside active organisation | Access denied with appropriate error message | API rejects unauthorized requests; logs generated |
How to use this contract
- Integrate these states and checks into your development and QA processes.
- Use the validation criteria as acceptance tests.
- Adapt the contract to your specific SaaS platform and user roles.
Worked Example: User Switching Organisations in a CRM SaaS
Consider a CRM SaaS where a sales consultant works for two companies, OrgA and OrgB.
- Upon login, the consultant selects OrgA as active.
- The dashboard shows only OrgA's customers.
- The consultant edits a contact for OrgA and saves.
- The consultant switches to OrgB mid-task.
- The system prompts to save changes; consultant confirms.
- The UI updates to OrgB's customer list.
- Any attempt to access OrgA's data now is rejected until OrgA is re-selected.
This is the intended workflow. Test delayed responses, writes and exports before claiming that the implementation preserves scope.
Additional Considerations
- Verify membership and operation on the server; do not trust user-editable metadata or an unchecked organisation header.
- Audit logs should record the organisation context of all user actions.
- For file storage, use access control policies to restrict files to the active organisation (see Supabase storage access control).
- Educate users on the importance of selecting the correct organisation.
Related Resources
- Learn more about SaaS development best practices in our SaaS Development Guide.
- Understand the trade-offs between CMS and custom development for SaaS platforms in CMS vs Custom Development.
- Plan for ongoing support costs with insights from Website Maintenance Costs.
- Improve user workflows with User Journey in UX Design.
If your business needs help implementing secure multi-organisation user contexts or SaaS development, get in touch with our experts via the SaaS Development Service.
Implementing Secure File Storage per Organisation
When users work across multiple organisations, file storage must also respect organisation boundaries to avoid accidental data leaks. Using a system like Supabase Storage with Row-Level Security (RLS) policies allows you to enforce organisation-specific access controls on files.
Key Implementation Decisions:
- Bucket Structure: Create separate buckets per organisation or use a shared bucket with organisation-specific folder prefixes.
- RLS Policies: Define policies on
storage.objectstable that restrict file access to the active organisation ID linked to the user's session. - Upload Permissions: Allow users to upload only to folders or buckets associated with their active organisation.
- Download Controls: Use signed URLs with expiry for private files, generated only if the user’s active organisation matches the file’s organisation.
Verify storage scope without trusting upload metadata
Supabase's Storage access-control guide describes policies on storage.objects. The application supplies the tenant relationship; Storage does not automatically interpret an active-organisation header.
Use a server-owned object-to-organisation mapping or another validated ownership model. Do not let an uploader assign arbitrary organisation metadata and then treat it as authorisation. Check current membership and the requested operation before signing a download.
A signed URL is a bearer capability, as described in Supabase's download guidance. Switching organisations does not bind or revoke a previously issued link. For per-request access checks, specify authenticated delivery and test cache behaviour.
Pin the organisation to requests and jobs
Capture the organisation when a form, upload or export begins. Do not read a mutable global selection when a delayed request completes. If Alpha's save is in flight while the user switches to Beta, that authorised write must stay scoped to Alpha and its response must not populate Beta's screen.
Do not assume a custom database session variable is request-scoped. Verify server-set context, transaction boundaries and connection-pool reset behaviour. Client-selected context needs authorisation before reaching a query.
Isolate stale responses and key caches by identity and organisation. Define whether an unfinished task completes under its original scope or is deliberately cancelled. Cancelling a browser request does not prove the server rolled back a write.
Acceptance procedure for switching
Use distinct Alpha and Beta fixtures. Test allowed reads/writes in each, then switch while an Alpha request is deliberately delayed. Its result must not render under Beta, and any completed save must retain Alpha's scope. Repeat for uploads, exports and queued jobs.
Remove a membership during the test. Try the existing JWT and a refreshed session because JWT claims may remain stale until refresh; Supabase's RLS guide documents this distinction. Define revocation separately from the organisation switch.
Multi-Organisation Interaction Contract: Detailed Workflow and Acceptance Tests
Building on the earlier contract, here is a detailed hypothetical workflow with acceptance and failure tests.
Hypothetical Case: User "Thandi" Working for OrgX and OrgY
Thandi is a product manager with access to two organisations: OrgX and OrgY.
| Step | Action | Expected Behaviour | Recorded Fields | Acceptance Test | Failure Test | Recovery Step |
|---|---|---|---|---|---|---|
| 1 | Login | Prompt to select active organisation if multiple exist | Active organisation ID stored in session | Session contains active_organisation=OrgX after selection |
No organisation selected; UI warns user and blocks further actions | User prompted again until selection made |
| 2 | Data Read | Dashboard loads only OrgX data | API requests include active_organisation=OrgX header |
Data fetched matches OrgX records only | Data from OrgY or others appears | Backend rejects unauthorized data; UI shows error; session reset |
| 3 | Edit Record | Save remains scoped to the authorized OrgX request | Request ID, captured organisation and version | Only intended OrgX rows change | Other organisation rows change | Pause the path, inspect commit state and use controlled repair |
| 4 | Switch Organisation | Resolve unsaved changes and isolate in-flight OrgX work before showing OrgY | Old/new organisation, task ID and draft decision | OrgY screen never renders delayed OrgX results | Lost draft or stale OrgX response under OrgY | Restore only the correctly scoped draft and retest delayed responses |
| 5 | Export Data | Export includes only OrgY data | Export API filters by active organisation | Exported file content matches OrgY data only | Export contains mixed org data | Export cancelled; user notified; logs reviewed |
| 6 | Unauthorized Access Attempt | User tries to access OrgX data while active org is OrgY | Access denied with error message | Endpoint returns its agreed deny response without protected data | Access granted erroneously | Inspect scope enforcement, repair and retest |
Worksheet for Multi-Organisation Interaction Contract Implementation
| Field | Description | Example Value | Notes |
|---|---|---|---|
| User ID | Unique identifier for the user | thandi-uuid |
Must be consistent across sessions |
| Organisation ID | UUID of active organisation | orgx-uuid or orgy-uuid |
Set explicitly on login and switch |
| Session Context | Stores active organisation | { activeOrganisation: 'orgx-uuid' } |
Backend validates membership; DB context must be request-scoped |
| API Request Header | Contains active organisation | X-Active-Organisation: orgx-uuid |
Backend validates this against user permissions |
| Database Session Variable | PostgreSQL session variable | SET app.active_organisation = 'orgx-uuid'; |
Illustrative context; verify trusted assignment and pool reset |
| UI Organisation Display | Visible label/logo | OrgX , Active | Must be prominent and persistent |
| Unsaved Changes Flag | Tracks form state | true or false |
Used to prompt before switching orgs |
| Audit Log Entry | Records user action with org context | { user: 'thandi-uuid', org: 'orgx-uuid', action: 'edit_contact' } |
Troubleshooting evidence, not proof of compliance |
Recovery Steps Summary
- On failed organisation switch, restore previous session context.
- On unauthorized access, log event, deny request, and notify security team.
- On data export errors, cancel operation and inform user.
- On file storage access failure, deny access and audit.
Use this proposed contract to test multi-organisation scope, current membership, delayed work and cache separation. It identifies controls and evidence to collect rather than guaranteeing that data mixing is impossible.
Documentation boundaries for this decision
Supabase's row-level security (RLS) enables enforcing strict access controls on database rows based on the authenticated user's context. For ordinary roles, tested grants and policies can constrain rows to a server-authorized organisation context. This does not automatically cover every read, write or export path; verify the execution role and each route independently. However, RLS policies must be carefully maintained and tested, as service roles can bypass them and JWT claims may not refresh immediately after membership changes. Source: Supabase row-level security
PostgreSQL's native row security policies provide granular control over which rows a user can access or modify. When row security is enabled, applicable ordinary-role operations are evaluated under policies scoped to roles and commands. Grants and privileged-role exceptions remain relevant. This mechanism supports enforcing an explicit active organisation context by creating policies that restrict data visibility and modification to the current organisation. It is important to note that superusers and roles with bypass privileges are exempt from these policies, and enabling row security requires owner privileges. Source: PostgreSQL row security
Supabase Storage integrates with Postgres RLS to control file access per organisation. By tagging files with organisation IDs and applying RLS policies on the storage.objects table, you can restrict upload, download, and modification permissions to the user's active organisation. The application must authorise link creation. Once issued, a signed URL is a bearer capability, not a check of the holder's active organisation. Test trusted ownership mapping, current membership, actual credential role and link/cache behavior separately; the setup description alone does not establish file isolation. Source: Supabase storage access control
Frequently asked questions
How can I ensure data is never mixed between organisations?
Require a server-authorized organisation context for every operation, capture it for in-flight tasks, isolate caches and visibly identify it. Verify positive and denied flows, delayed responses, exports and membership changes; no design description proves that data can never mix.
What if a user forgets to switch organisations before working?
Design the UI to make the active organisation highly visible and confirm organisation switching with warnings when unsaved changes exist.
Can row-level security (RLS) help with organisation data isolation?
Yes, RLS policies in databases like PostgreSQL or Supabase can enforce strict data access rules scoped by organisation ID.
How do I handle file storage for multiple organisations?
Use storage access control policies that restrict file access based on the active organisation and user permissions.
Related guides
For further background, read our cms vs custom development and website maintenance costs. The user journey glossary explains the terminology used in those guides.

