How to store user information

I am new to Auth0 and am working through a somewhat basic starter project just to get the hang of things. It is a basic social media project that consists of Auth0 (obviously), a React app on the frontend, and a Node.js GraphQL backend API. I am confused on how to relate user profile information to application data.

For example, given that I am using GraphQL, I want to be able to make a simple request that fetches a list of posts and the corresponding user that created the post.

The way I see it is there are two options. One, I keep a user’s table in my database that holds a user’s basic information such as id, username, first name, last name, etc. Then, on the GraphQL query, I can fetch the user’s information from the database easily. The other option is to not store the user’s information, and instead, make a request to the Auth0 management API to get user information.

In either case, I see a big issue. With the local user table, how do I keep this information in sync with the user’s information in Auth0? I could update the user’s data every time they make a request with my Node API, but isn’t this expensive to do on each request? If I use the management API, I then have to reach out to the rest API for each user which can be very expensive for a GraphQL request.

For both scenarios, what if a user gets deleted? How do I propagate these changes to my database so that their posts and any other data gets deleted.

In general, I am looking for a best practice to associate a user’s information to their data in my database and how I handle issues of keeping data in sync when a user updates their data or deletes their account. Thanks for any help.

Note - I do not wish to use the custom database feature.

6 Likes

Does anyone have any advice on this? Thanks.

1 Like

Hello @ryancat.dev (nice .dev domain, by the way!).

Every user who logs into your app has a unique identifier (the sub claim in their ID token). When a user authenticates, if you’re using the auth0.js JavaScript SDK in your React front end, your app can receive the user’s decoded ID token. You can then use their ID (the sub property of their idTokenPayload object in the authResult) to associate a user with their data in your database.

When you make requests for a specific user’s data (or perform other CRUD operations), you can request/update the data by ID, which you will have access to upon login. You don’t need to use the management API to do this, nor do you need a local database of users, you can just make direct API calls.

Regarding user deletion: is this an action that an admin of your app would be able to perform? Would this be happening through the management API, or the Auth0 Dashboard? Your context and architecture would drive what approach would be the most advisable in that particular scenario, so if there’s more information you can share, I can help better.

Please let me know if this helps answer your question, or if there’s anything else I can clarify.

2 Likes

Thank you @kim.maida for the response! I do have a few follow-up questions.

Let me make sure I have creating/updating users in my database correct. You suggest that when a user makes a request to my GraphQL API, at the start of every request, I should:

  1. Check if the user exists. If not, create the user in my database.
  2. If the user does exist, update the portion of their profile information that I am storing in my database to match their profile information in Auth0.

Is that what you recommended? Just want to make sure I am following it correctly.

If so, I feel like doing this on each request is kind of expensive. Do you disagree?
Also, kind of an edge case, but what if the user signs up/changes their profile information, and then never does anything else. Now since they have not done anything to make a request to the API, Auth0 and my database will be out of sync. Is this just something I have to live with?

In terms of deleting, the user should be able to delete themselves from the application through the React app (by clicking a button for example). When doing so, they should be deleted from Auth0, so that they can no longer log in, and all their associated data (posts, comments, followers, etc.) should be deleted from my database so that other users can no longer see their data. An admin should be able to delete a user as well and the same deletion flow should occur.

In general, I really do not care how a user gets deleted (user through React, admin through dashboard, admin through management API, etc.) as long as that deletion flow happens when a user gets deleted.

Thanks for the help.

Hi @ryancat.dev, no, that’s not my recommendation. Without a deeper understanding of your API and application architecture, it can be a bit difficult to generalize, but you should not need a local user database; the purpose of Auth0’s user database is to do that for you. You may want to create associations by user ID with their data in your local database, which you can do in a variety of ways.

Perhaps you can tell me a little more about your app’s application data: what actions can a user take? What data do they need to be associated with from your API? Once I know these things, I can offer more precise guidance.

@kim.maida I understand its difficult to give guidance without a deep understanding, so thank you for trying thus far. However, it’s hard to give you exact details because it is just more of a sample project to learn how to use Auth0, but I will try.

I was just planning on creating something basic like a Twitter replica. A user can follow users, tweet, comment on tweets, retweet/like tweets, etc. All that information is managed through my GraphQL API and stored in my database. All that information needs to relate to a user. For example, a tweet needs to reference the user who created it. A follow needs to reference the user who is doing the following and the user being followed. And so on.

I see you are stressing not to keep a local copy of the users information in my database. This makes sense because then I do not have to worry about anything when a user is created or updates their profile (still confused about deletes). However, that means that I need to make calls to Auth0 through the management API to get user information. I feel like this is not good if I have a GraphQL request to fetch a list of posts, and for each post, get the user who created the post. That means for each post I need to query with the management API which I feel could be expensive. In other words, if I want to list 10 posts, I need to call the management API 10 separate times to get the user who created the post.

I hope this helps you understand more. Thanks for your continued help.

Thank you, that helps me to understand your scenario! Just keep in mind that a Twitter replica is not particularly basic because of the amount of relational user data that is involved. Honestly I would recommend starting with the simplest implementation and then scaling up by features. For example, users deleting themselves may be something to implement later. You may want to start with features that don’t require the management API, and then scale up.

That being said, let’s break it down a bit — and I will go back on some recommendations I made initially, now being more fully aware of your goals. I hope that is alright! Context is everything. :slight_smile:

You mentioned not wanting to use the custom database feature. However, since you do want to store and access user information frequently, it does seem that you will want a local database of userinfo (just without any authentication information in it). You’ll need to make a decision on how you want to manage your user information, some of your options being:

  1. keeping your own db in sync with the Auth0 user database, potentially using user_metadata (this is a question you were asking: “how do I keep the two stores in sync?”)
  2. allowing your app’s user profiles to be separate from Auth0’s database of users, and associating the two databases by user ID solely for authentication purposes (purposefully not keeping them in sync)

While option 1 is totally possible, I wouldn’t recommend it as a basic implementation to learn about Auth0. Option 2 is likely the most simple to implement and the most straightforward, as long as any dev working on the app is fully aware of this architecture (sounds like this is only you, and therefore won’t be a concern). There is no requirement to keep those databases synchronized, and in your case, you may actually not want to have to worry about doing so!

Having a database of user profile information negates the need for calling the management API in this scenario for getting / updating user info, as long as you are comfortable with the Auth0 database userinfo not matching the user information you need for your application. This may be just as well, since you most likely want your users to be able to have information like a link to their website, a short bio, number of followers, number of people they’re following, etc. (none of which exist in the Auth0 user database and would require user_metadata or app_metadata to add anyway).

The use of GraphQL, I assume, makes associating user information from your own API the ideal solution, if you remove the need to worry about the management API at all with regard to getting and displaying user profiles.

Regarding the deletion of users, that does indeed need to be done using the management API. You will delete users by their unique ID, and since you’ll have associated the Auth0 user ID with their user info in your database (and assumably, also their tweets), it should be straightforward to make a call to your own API that removes those entries before calling the management API to remove the current user from Auth0.

Please let me know if this makes sense or if there’s anything else I can help with!

1 Like

@kim.maida Wow. Thanks for the detailed answer and your continued support. I appreciate it. I could probably ask dozens of more questions, but I will try to limit them.

The options for how to store user information make sense to me and were basically the two options I saw as well. I am torn because I like having the user’s information in Auth0 right by their account information. Also, if I want some of my users’ authentication/authorization information available to my GraphQL API such as email or username, then I still have to query the management API I guess.

You also seem to state that option 2 is the better for learning because it is more straight forward. So tough question, would you say that option 1 is a better option overall for a production level application? Obviously, like I said, I am working on a sample application now, so option 2 is going to be easier and better for that. But for building a real (not a sample) application that people will actually use, seems like you are implying option 1 is “better”.

You’re explanation on deleting makes sense to me. One thing though, in the rare occurrence that the call to the management API to delete a user fails, and I have already deleted all their information from my database, now what happens (another tough question)?

Maybe my problem is trying to generalize a solution for various situations, and that I am new to this but thanks again.

Hi @ryancat.dev, I’ll do my best to address your follow-up questions:

I am torn because I like having the user’s information in Auth0 right by their account information. Also, if I want some of my users’ authentication/authorization information available to my GraphQL API such as email or username, then I still have to query the management API I guess.

You can actually grab any information out of the user’s Auth0 user info to do things like pre-populate info you’ll want to save to your own database. For the sake of example, let’s say you want to save their name and email from the social identity provider profile they signed up with (e.g., info from Auth0 user database). To create a hypothetical flow, consider this:

  1. User signs up to your app and uses Google as an IdP when they log in with Auth0.
  2. Once they’re authenticated, you have access to their idTokenPayload object, which contains their existing Google profile data in your application.
  3. Maybe as a first step, you want them to fill out their profile, so you display a form that asks for their name, email, website, etc.
  4. Because you have access to their Google profile info, you can pre-populate some form fields for them using that info from their Auth0 login. They can then change those, or accept the pre-populated values.

would you say that option 1 is a better option overall for a production level application?

I would not say that option 1 is better for a production level application in a blanket sense, no. It’s a bit of a nuanced situation, so what you’ll want to consider is what the tradeoffs are, and what your (and your team’s) preferences are. I personally have built and deployed production applications using option 2 and have been very happy with the architecture. Here are a few things to consider.

Option 1:

  • No confusion over what data is where when the user is concerned: it’s all in one place. Any new devs coming onto the project won’t be confused about where user data is being kept (however, the flow to update and retrieve it is more complex, so they will need to understand that).
  • Changing a user’s data in Auth0 using tools like the Dashboard will ensure the data is also changed in your app.
  • Getting user data for users who are not the currently-logged-in user into your application requires calls to the management API.
  • Updating any user data requires calls to the management API.
  • Centralized user data if SSO is (or becomes) a need. This could be an advantage OR it could be a drawback, depending on if you need SSO authentication, but want to keep different user information per SSO-enabled app or not.

Option 2:

  • Auth0 user database can help to pre-populate initial user info, but may get out of sync with application-level user information. Devs coming onto the project need to be aware of this so they aren’t confused by the differences.
  • Changing a user’s data in the database will not change their data in Auth0 unless a call to the management API is made.
  • Updating or viewing user data in the database does not require management API calls.
  • Simpler implementation, especially for GraphQL. (Simplicity is still good on production, not just in development!)
  • (Point about SSO also applicable here)

in the rare occurrence that the call to the management API to delete a user fails, and I have already deleted all their information from my database, now what happens (another tough question)?

That’s a great point. You could do these in reverse order, and set up a promise, callback, or observable (pick your poison!) that deletes the local database information only if the management call has succeeded.

Maybe my problem is trying to generalize a solution for various situations

It’s tricky because generalizing a solution can sometimes back you into a corner. For this particular scenario though, our conversation so far outlines most of the things you’ll want to consider. I think what you’ve done by considering your scenario and architecture and overall goals, and then looking at how the tools can help you achieve them, is the right approach.

1 Like

@kim.maida Thank you for the detailed response. I still feel as though I see critical issues with either way. Maybe I am just not understanding. But I will ponder over this. Thanks for the help.

@ryancat.dev One thing I would try to make sure to do if you choose option 1 (and would likely recommend for option 2 also in a standard API/database scenario, though GraphQL may negate the need for it) is to ensure that each tweet has a minimum amount of author information in it for timeline displays (e.g., the author’s handle and username). That way, when displaying a feed of tweets, you aren’t doing a user lookup for every single tweet.

If the author then updates their userinfo, you can do a query in your backend and update the info in their tweets, but ultimately, you’re only grabbing the full user data for users when their profile page is being viewed.

In any case, there are many ways to tackle this, and different people will certainly take different paths depending on their personal preferences. Lots of things to consider here. You can also check out features like Rules and Hooks to get some ideas for things you can do when users authenticate or register.

Best of luck!

1 Like