---
title: "Comment by Ascendra Ventures on \"Multi-Tenant SaaS Security Starts in the Data Path, Not the Login Form\" | Hashnode"
description: "The /invoices/4821 example is the bug that shows up in almost every early SaaS review. Login passed, the session is valid, the invoice exists, and none of that"
url: "https://hashnode.com/posts/multi-tenant-saas-security-starts-in-the-data-path-not-the-login-form/6af18d2afa5fb851e54e30b7/comment/6af282fa271b5a1a03d517aa"
---

[Discussion](https://hashnode.com/posts/multi-tenant-saas-security-starts-in-the-data-path-not-the-login-form/6af18d2afa5fb851e54e30b7)

Comment [Multi-Tenant SaaS Security Starts in the Data Path, Not the Login Form](https://hashnode.com/posts/multi-tenant-saas-security-starts-in-the-data-path-not-the-login-form/6af18d2afa5fb851e54e30b7)

[Ascendra Ventures](https://hashnode.com/@ascendra-ventures)

[1d ago](https://hashnode.com/posts/multi-tenant-saas-security-starts-in-the-data-path-not-the-login-form/6af18d2afa5fb851e54e30b7/comment/6af282fa271b5a1a03d517aa)

The /invoices/4821 example is the bug that shows up in almost every early SaaS review. Login passed, the session is valid, the invoice exists, and none of that says it belongs to this tenant. Hiding it in the frontend only means nobody has typed the number yet.

Resolving tenant context from server-side membership instead of a tenant\_id in the request is the right default. I would add one habit: for every endpoint that reads or writes by ID, keep a test that logs in as tenant A and asks for something owned by tenant B. It is cheap, and it catches the one endpoint someone added in a hurry.

At Ascendra Ventures we put that cross-tenant check in the acceptance cases of any SaaS build, because retrofitting isolation after launch costs far more than designing for it in the first version.

Do you prefer enforcing this in the application layer, or pushing it down to row-level security in the database as a second line?
