Laravel SaaS Application: Ensure Users of One Tenant Cannot See Other Tenant Pages
We are partnering with a client to build a SaaS product that we are really excited about (and hope to announce more details on soon). It is a multi-tenant application where each new tenant gets their own subdomain.
It is critical that authenticated users can only see data from their own instance. What if a user is authenticated into the application at tenant1.domain.com/dashboard and changes the subdomain in their browser to tenant2.domain.com/dashboard? We need to make sure this user cannot access any page outside of their own domain.
As with all of our clients, we are building the product on Laravel. Here is the design approach we took.
Set the Subdomain in the Session
The first step is to set the domain in the user session once they are logged in. That means accessing the LoginController and updating the authenticated function. This function is called immediately after a user is successfully authenticated.
We placed the following line of code here to set the subdomain in the session:
If you don’t understand that code, keep reading because I break it down when we create the middleware.
Create Middleware to Check Each Request Subdomain
Now that we have stored the authenticated subdomain in the session, we need to create a middleware to get the subdomain from every request and compare against the value we just stored in the session.
First we create middleware using the artisan command make:middleware
Then we open this middleware and add the following code:
Now we just need to apply this middleware to every web route. You may already know how to do this, but just in case you don’t, here are the next steps.
Apply Middleware to Web Routes
Right now the middleware we created isn’t being called anywhere. We can to add this middleware to every web request (meaning non-api requests). To do this, open the Kernel.php file in the app\Http directory and you’ll find a middleware groups variable. All you need to do is add your newly created middleware to this array.
Your array may look different than mine below, and if so that’s okay. Just add your new middleware to the end of the array.
That’s all it takes to ensure an authenticated user on one subdomain cannot process web requests from other subdomains. This is a great step in building a multi-tenant SaaS application with Laravel.
Please keep in mind, there are many other considerations to ensure users in your SaaS application only see the data they are supposed to see. We have assigned Global Scopes to all relevant Models, and comparing the tenant_id in those models to the tenant_id for the authenticated user. Lastly, if you have API requests you will want to protect those as well, which may be another blog post entirely.