Postgresql – Handling user logins while using a multiple schema design to support multi-tenancy

loginsmulti-tenantpostgresqlschemausers

I'm creating a web application (in PHP and PostreSQL) that will be used by organisations and their staff and I want to use multiple schemas to support multi-tenancy. There will be one database and I want all data related to organisation A to be stored in a schema named A and all data for organisation B to be stored in schema named B etc..

What's confusing me is how to handle user logins. Let's say Amy is a member of Organisation A and Ben is a member of Organisation B. When Amy goes to example.com to access my web application she's presented with a login form, which asks for her username and password. Now, Amy's username and password is stored in the users table of schema A but how does the web application know where to look to authenticate her?

I've never used multiple schemas in a web application before so in the past I would create a fixed username, i.e. webapp for the application, which would log in and check the credentials supplied by Amy against the data stored in the public.users table (where public is the default schema created by PostgreSQL) but with the design I'm thinking of using, there is no way to tell which schema Amy belongs to and as a result, it wouldn't be easy to find the correct users table to authenticate her.

One approach would be to stop using a users table for authentication and create a role with the LOGIN privilege for the database for every user, then only give that user permission to interact with the appropriate schema. That's a solution I've seen but not one I really want to use. I assume there's a better way but I just haven't been able to find it.

So, to summarise, all I want is for users to be able to log in to my app via the web interface and be restricted to the schema of the organisation they belong to. What's the best way to accomplish this, bearing in mind I intend to have several organisations and users in the long run.

All help is appreciated. Thanks in advance.

Best Answer

Your options are:

  • Use roles, and SET search_path on each role so it looks in the appropriate organization's schema. While in many ways the cleanest approach from a database perspective, this is a pain when giving orgs the right to manage their own users.

  • Require users to specify their organisation at login time, probably with user@domain style logins, or using mycompany.myhostedapp.com style URLs. Then look up the org by @domain suffix before authing the user against that org. That's probably what I'd do.

  • Create a view that's a union of all company user tables and look users up in this. Likely to be a performance nightmare, and how will you handle duplicates?

  • Create a parent table for all user tables, make all the user tables inherit it, and query the parent table. Just a slightly more efficient version of the view approach, not recommended.

I strongly suggest an authentication design that carries the company identity of the user along with their login request.

Related Question