-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Singleton ApolloClient instance approach, potential issues? #360
Comments
Hey @ViktorShev 👋 We don't recommend you share the same instance between requests otherwise you risk leaking user data. If you're authenticating once outside of a request, only a single user could login to your app at a time (or at least one user per running server instance). Even if you managed to solve that issue, using a single instance of the client means that you would be merging multiple user's data into the same That If you're trying to avoid making that authentication call to the remote service on every request, I'd recommend caching and storing that value outside Apollo Client with something like Redis or your own key/value store that can distinguish between users. |
@jerelmiller Hey! thanks for the quick response. I don't seem to be experiencing any of the issues you mention, I am still able to log in into my application with different users and interact with it in parallel, checking the Apollo cache of each browser instance they also don't seem to be leaking into each other, be it after running mutations or querying data: Maybe I missed some details in my initial issue, would you like me to provide some more clarity on anything? I understand this might not be the best approach and will be looking into something else, but now I'm intrigued as to why this seems to be working. |
Ah I missed the As for your screenshot, you're not going to see issues on records that have different cache IDs, like the user records themselves. Where you start to get issues with data leaking is when you're querying for records that have user-specific data attached to a shared entity. As an example, let's say you have a schema like this: type Query {
post(id: ID!): Post
}
type Post {
id: ID!
canEdit: Boolean!
contents: String!
} where And let's say that when users visit a particular post, it issues the following query: query($postId: ID!) {
post(id: $postId) {
id
canEdit
contents
}
} Now let's say the author of post
Now lets say another user logs in and visits the same post, which issues the same query. Because we can fulfill the data from the cache, this means that we return the cached data for that post. Oops, now we've just given that user the ability to edit that post. Its these types of situations where having a shared cache for all users can be dangerous. Its very common that at least some of your records are visible among a subset of your users, and also common that your schema embeds user-specific information with those in some form. You can imagine how bad it might be if those records contain PII. Does this help illustrate the situation? |
Okay that makes a lot of sense now! I will be closing the issue now as it is very evident that this approach can cause some big problems. Thanks for your time! |
Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better. |
You're welcome! Glad that helps 🙂 |
I would also recommend that you look at this comment for an alternative pattern - you would set the auth token on the client after the client was created by |
Could this approach present any issues? In a previous project we had kind of the same set up with Next's page router, where we shared the same Apollo instance throughout the application without any issues.
Currently we are using NextJS 14 with the
app
routerMy use case is that I need to use the same
ApolloClient
instance outside the context of React, more specifically, I have anFirebaseAuthenticationProvider
class that has a method to retrieve the current user's database ID. The user token in sent automatically through auth link.This class is retrieved through a function that will only instantiate the class IF there was a change in authentication state (e.g a user logged in), this ensures that the class will not "operate" on methods without a user, if the class is available, it means there is a user.
And is used on my authentication link like so:
the method
authProvider.getToken()
does not have a backend request, that's why I'm able to callgetToken
without falling into a circular dependency of needing Apollo already set up in the auth provider for backend requests and the auth provider being needed for setting up Apollo.The reason for needing the same instance throughout my application is so that once the authentication provider fetched a user from the backend, it can cache it and not hit the server every time I need to retrieve some user information again due to
makeClient
returning a different instance with a new cache.Note: I imperatively clear the cache on user log out with
.clearStore()
I assume this won't have problems with SSR either since the
InMemoryCache
from the experimental package acts a "enqueuer" of cache writes during SSR, and once we are in the client context, the cache is restored by executing those writes, unless I understood the RFC incorrectly: https://github.com/apollographql/apollo-client-nextjs/blob/pr/RFC-2/RFC.md#library-design-regarding-ssrAlso looking at the source code the
ApolloNextAppProvider
reuses the same client instance as a singleton too.So far I haven't noticed any problems besides not being able to call
makeClient()
in server components like a layout, Next throws a webpack error:But just wanted confirmation if my assumption is correct and if there could be any other potential issues with this pattern (and potentially a hint towards fixing the webpack error 😬)
Thanks!
The text was updated successfully, but these errors were encountered: