Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

thebigk's avatar
Level 13

Multiple Apps User Permissions Conundrum

I'm building an 'app' of 'web-apps' and after making significant progress, I'm back to deciding if I've opted for the right structure for user permissions. I'd really appreciate help from fellow members in figuring out potential problems with my current approach and maybe suggesting a better one.

App Structure:

[Main App]
-> App I
-> App II
-> App III
-> App IV
....and so on. 

While logged in users will be able to access all the apps, most of the apps will need a few users with special permissions.

Example:

App I -> App1Admin , App1Moderator
App II -> App2Author, App2Editor
App III -> App3StoreManager, App3Buyer
etc. 

Now my current approach is to have a single table to store and reference the roles:

role_users (pivot table)
user_id | role_id

The pivot table will use user_id from users table and role_id from roles table where I'll only add different roles like

roles
id | name
1 | App1Admin
2 | App3StoreManager
3 | App2Editor
etc. 

However, I'm not sure if this is the right direction to take. Maybe, another (possibly better) approach is to have special tables like:

app1_roles

user_id | role_name
1 | App1Admin
1 | App1Moderator


app2_roles
user_id | role_name
1 | App2Author
2 | App2Editor

and so on.

I'm not at all sure which approach I should take. It's first time I'm ever designing such an app of 'apps' [ Think of it as a Google Play store for web-apps ] .

Could you please help me figure out the right approach?

0 likes
8 replies
lostdreamer_nl's avatar

The system you're designing now is called a 'multi tenant system', I suggest reading a bit about it.

I would never design such a system with different tables for each of the tenants (apps), just think about all of the tables being dynamicly created and destroyed when you add / remove apps (which should only be a matter of adding a few rows to some tables in the DB).

The way you have it right now is the right way, but most of the multi tenant systems I know dont have different "types" of admins for instance, so I would not design it with an App1Admin role and an App2Admin role if possible.

I'm just guessing there might also be a need for 1 person having roles in multiple apps.

// Roles:

id   | name
---- | -------------
1    | Admin
2    | Moderator
3    | Editor

// role_users

app_id    | role_id  | user_id
--------- | -------- | ----------
1         |      1   |       1
2         |      1   |       1
3         |      1   |       1
3         |      2   |       5
1         |      2   |       8

User 1 is an Admin in all 3 Apps, App 1 and 3 have different Moderators.

Then in the roles() method on the User model you can add a check to see in which app you are currently and add the wherePivot() to select only the roles for the current app.

thebigk's avatar
Level 13

@lostdreamer_nl - yes, it's indeed a multi-tenant system. About the app roles, 'App1Admin' and 'App2Admin' are basically the users who have 'higher' levels of access for those specific apps. For example, two actual apps in the system are:

  1. Discussions
  2. Events

For discussions app, I'll need a few users to play the 'admins', so that they can add/remove moderators for the discussion apps. These admins will be limited to the 'Discussions' app and their capabilities will be limited to that app.

For events app, I'll need to have 'EventCreators' role so that those users can create events and 'EventAdmins' who can edit/delete spammy event data.

|| I'm just guessing there might also be a need for 1 person having roles in multiple apps.

Yes, that is likely to be a common case. An 'admin' in Events app can be a 'EventCreator' in Events app.

The way I'm doing it currently is that I check the user role through a middleware :

Route::get('route', 'Controller@method')->middleware('RoleCheck:Admin,Editor,Author');

Since I'm keeping the role names specific to apps, I can control who gets access to which app. I'm now wondering if there are more advantages to having a three-table column with app_id | role_id | user_idas you suggested.

BezhanSalleh's avatar

i would do as @lostdreamer_nl suggested, and instead of to many tables just classify your roles

id   | name
----| -------------
1    | super_admin
2   | app_admin
3   | event_admin
4  | other_role

this way you will only have couple of more roles and its easy to adjust way more better than the table thing...

thebigk's avatar
Level 13

Thank you, @Yama . A realistic estimate is that we'd have at max 4 (rare) roles and most app would have 2-3 roles.

I now see some merit in the first approach and still have to figure out what could possibly go wrong.

lostdreamer_nl's avatar

Not much that can go wrong, but a thing to keep in mind is if it would / should be possible for a Moderator in App 1 to have different permissions in that app than a Moderator in App 2 has.

If that would be the case, then you would also need to have a Permissions table, and link them (belongsToMany) with the role_users table (so you'd have to create a Model for the pivot table as well, and give them unique IDs).

That way you can have different permissions on the same role in different apps.

Ofcourse, in your code you should then never check if a user belongs to a certain group, but rather check if the user has a certain permission (via 1 of it's groups) in the current app.

It's a very nice / open way to build the permission system in a site.

thebigk's avatar
Level 13

@lostdreamer_nl , thank you once again. As I said, my main worry now is to figure out cross-app permissions. Yes, a moderator in App1 can have different permissions in App2. As of now, my approach is to name the roles starting with their app names:

  1. App1Admin
  2. App2Editor
  3. App4Manager

Any member of the site can have all the above 'roles'. In any app, I'll be checking for specific role names so that there is no confusion. I've tried this approach with my test apps (only 2 so far) and haven't found any issue.

Example:

route::get('app1/admin', 'App1AdminController@index')->middleware('RoleCheck:App1Admin,Aap1Moderator')

route::get('app2/admin', 'App2AdminController@index')->middleware('RoleCheck:App2Editor')

My best guess is that with this approach, I'll only have to keep adding roles in the 'roles' table.

Could you please let me know your thoughts on this approach, vs having a separate permissions table?

PS: Wishing you a very happy new year!

lostdreamer_nl's avatar

@thebigk Happy new year to you to :)

When setting it up in the way you're doing now: you will have to be involved in the project throughout it's lifetime: Every time when a new app is setup, and it's users / admins need to have a role slightly different then the original one, you will have to add that role, and setup a lot of checks in your view.

ie: We have posts, all users can create posts, but the have to be accepted by an editor or admin, and editors can edit anyones post. Your edit / update route will now probably have a check like:

if($user->hasRole('admin') || $user->hasRole('editor')) {
    // do stuff
}

Now app2 wants to have Managers that can also do this. You have to add the role (App2Manager) and edit all of the places for the logic:

if($user->hasRole('admin') || $user->hasRole('editor') || $user->hasRole('App2Manager')) {
    // do stuff
}

This will go on and on.

The suggested way would be to not check for a role, but for a permission:

if($user->can('edit-post')) {
    // do stuff
}

Now you can have a table with Permissions, and a pivot table permission_role to link the permissions to certain roles.

So now, when a new app is setup, the admin of that app can go into the administration panel, edit the default roles and setup the needed permissions as they see fit.

They can even create new roles, and select which Permissions should be available to that role.

This way there doesnt have to be a developer involved everytime a new Role (or actually a group of permissions) is needed for any app.

thebigk's avatar
Level 13

Thank you, @lostdreamer_nl , you have a point. However, each app is independent on its own. I don't see any situation where App1 would need to check user's role on App2.

That is, if a user is an Admin of App1, App2 need not know anything about it. App2 will only care about roles specific to it. The only check required would be whether the user s logged in or not.

My initial plan was to do role checking directly on the route, and not inside the controller. I think I'll have to think about this a bit in more depth.

Please or to participate in this conversation.