This is my first time setting up OpenID Connect with IdentityServer 4 and AspNetIdentity and I was hoping someone could demystify the part about storing user data.
What I've read so far is that user data should be stored in the Auth db that is connected to the auth server, but I'd really like to store user data in the resource db too that is connected to the resource server.
I currently have a data model that looks like this:
I have omitted many of the fields for both User and Event, but you hopefully get the picture. We have a User table, an Event table, and a Host table. A User can Host an Event. The many-to-many relation between a User and an Event is via the Host table.
This is such a rudimentary question on architecture, yet it's really hard to find a good answer that makes sense and that isn't a total hack. So far I've read about the following solutions from different people:
Store all user data in the Auth db, only, and then set an API up on the Auth server so the Resource server can get data from the Auth server.
Someone else says that non-auth related data such as a user's city or country should not be stored in the Auth db. Instead keep auth related data in the Auth server only and any user-related data in the Resource DB. This sounds like the two User records need to be in sync? Sounds like a bad idea.
Have the Resource server and Auth server be one application so that we can build the necessary relations between User, Host, and Event. But this seems to defeat the whole purpose of using OpenID Connect.
So what is the standard architecture here? Or if there is no one-size-fits all, how would you store this user data?
With seperation of concerns and single responsibility in mind:
There is not just one user table. Fields in a table have only meaning within the context.
A user can have a google account to login, but for the business that is not the account where you can reach the employee. And how about showing information on a report that is not part of the context? Suppose you store city in the identity context. Then how are you going to show that information on a report? You'll need the information in the business context.
Also consider whether the identity context is a good place to store information. Because the user is in control. What happens when the user doesn't give consent for using the information, or simply removes the account? And what strategy to use when you would like to synchronize data?
Sharing contexts is a no go. Identity is the responsibility of IdentityServer, the identity context should only contain information about the identity and is only accessible by the IdentityServer. Please note that IdentityServer is not bound to one app.
You'll need a user table in each context. Where information may seem redundant but actually is not, because it is part of the seperate context. Like when you login using a provider like google. Then a local copy of the user is created in the identity context.
But perhaps you should not refer to it as User in the business context. Because within the business context there are no users. Most likely they are employees, customers, etc. Who can have a login, but not necessarily. And it's possible to have (identity) users that are unkown to the business (e.g. in case of multiple apps).
IdentityServer is the authority to authenticate the user. Authorization can be implemented on multiple levels. You can create a seperate authorization server (like policyserver). Or lower level (resource-based), where the existence of a user inside the 'person' table means that the user has access to the resource.
The best part of seperate contexts is that within the context you can create relations between tables, without interfering with other contexts. You can easily switch to a different oidc provider, if you'd like. But once you start to mix contexts, there is no way back.
The one thing that is very useful in oidc is the
sub claim. Simply look up the user by the
sub claim and use the local id for the business context.
About the fields
country in the identity context: there are multiple levels of authentication, so you may actually need the information in this context. But if you need the information in another context (e.g. to show on reports) then it should be added there (as well).
One extra option that I personally preferred using when faced with the similar problem was to simply share the identity database between various applications. This solved the problem of unnecessary duplication. However, if you go this way, you need to try and ensure that some sort of separation of concerns is maintained - identity management is not done by the resource server application and likewise resource related data management is not done by the auth application.