C
C#2mo ago
shadi

Multi tenant implementation & Security

sorry this is more of architecture question rather than C#, but I want to implement the following: A multi tenant app with 2 web apps (Dashboard and Core) The dashboard app lets you create an account, pay for a specific plan then create your own company with Company Name & Description. so you will have User, Company & UserCompany records added before you can access the other app. after you add your Company, a new CoreDatabase instance is created just for you, where then you can add branches, work items...etc. Now users who wish to be part of those "Companies" shall create an account on my Dashboard app, because I want the Users to be centralized and also allow some sort of mechanism that allows users to move between companies and also exist in multiple companies. But how do I reference the Users table that exists in the DashboardDatabase within each CoreDatabase? Do I just add a Users table in my CoreDatabase too and whenever someone applies for a company and gets accepted, I add [id, displayName, email & PortalUserId] (I will cache everything that's not id here to avoid lookup to the dashboard database from within separate apps) without any authentication there? is this valid? because I feel like there's duplicated data here, or is it not considered duplicated since it's a different context. If this is ok, how to handle security with JWT? if user A is part of both company X & company Y and the Roles & UserRoles table for each exist within each CoreDatabase that references the CoreUser shallow copy and not the DashboardUser how am I supposed to generate Claims here? or do I only generate a basic token that allows the user to see basic stuff like his Dashboard account details, list of companies he's part of and once he clicks GoToCompany I regenerate a new token with the old one adding the company specific claims? this is the only idea I have but I'm afraid I can't see some security breach here Thanks for reading.
No description
6 Replies
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
shadi
shadiOP2mo ago
in my humble opinion it's cleaner I implemented it with one database, then multiple, and i liked multiple better but that's out of the way since I already implemented the logic needed for database creation per tenant migrations switching connection strings at runtime...etc
Unknown User
Unknown User2mo ago
Message Not Public
Sign In & Join Server To View
shadi
shadiOP2mo ago
no I already implemented the rest of my application but it was different than what I want right now What I did was allow each core app to create and manage its own users and have their own sign in page where it's something like domain,com/api/sign-in/{applicationName} it was deployed and being tested but recently changed the hosts and I found it better for me business wise to do what I mentioned. no authentication on core level a shallow copy of user is added to the core database once they join or get registered by that core app to their db this way it still allows users management to be centeralized in portalDb while having a shallow copy of that user in each coreDb the user joins example:
//when user signs up to my platform, this record is added in my PortalDb
class PortalUser {
public int Id {get; set;}
public string Name {get; set;}
public string Email {get; set;}
}

//when user joins a company, this record is added in the CoreDb of that company
class CoreUser{
public int Id {get; set;}
//doesn't have a relationship, will rarely be used, but need to keep track of what this user represents in my portalDb
public int PortalId {get; set;}
//cached properties from portal
public string Name {get; set;}
public string Email {get; set;
}
//when user signs up to my platform, this record is added in my PortalDb
class PortalUser {
public int Id {get; set;}
public string Name {get; set;}
public string Email {get; set;}
}

//when user joins a company, this record is added in the CoreDb of that company
class CoreUser{
public int Id {get; set;}
//doesn't have a relationship, will rarely be used, but need to keep track of what this user represents in my portalDb
public int PortalId {get; set;}
//cached properties from portal
public string Name {get; set;}
public string Email {get; set;
}
Withi this logic I am simply asking whether what I am suggesting is correct or is there a better approach to implement it the way I described
ardalis
ardalis2mo ago
Just using a unique userId between databases should serve your needs architecturally. Copy anything else you need like email etc but not auth related columns. That works for authentication. For authorization it’s trickier. If a user belongs to tenant A and B and has tenant-specific roles in each it will be difficult to have your SSO find and capture all of these claims at login. However you can “upgrade” a token at a specific tenant with an endpoint that uses your identity token to identify the user and then returns a new token that adds the claims for that tenant. Assuming you’re ok with separate tokens per tenant this should work.
shadi
shadiOP2mo ago
I was going to do that too! have an endpoint that updates your jwt based on the core app you want to use and correct me if i'm wrong, but i was going to do the following setup on mobile app: user logs in, I already know what part of tenants he's in i give him a jwt token to use general features that's available to everyone regardless of tenants specific features then, there's a section in my app where it shows him what active tenant he wants to see/interact with right now (it will be a list, i already have them as claims in the general token) when he chooses tenant A, i get his old token and generate a new tenant specific token that has all that tenant claims for authorization purposes, and my mobile app will attach either general token or tenant specific token based on the api url if he deals with api/dashboard: general token if he deals with api/core: tenant token if he switches tenant, his tenant specific token will get updated and so on

Did you find this page helpful?