Automattic / mongoose

MongoDB object modeling designed to work in an asynchronous environment.
https://mongoosejs.com
MIT License
27.01k stars 3.85k forks source link

Auth support for `useDb()` #8116

Closed vkarpov15 closed 4 years ago

vkarpov15 commented 5 years ago

Re: #2874, useDb() should have the option to provide auth credentials in case the currently logged in user doesn't have access to the new database.

https://mongoosejs.com/docs/api/connection.html#connection_Connection-useDb

linuscarlstrom commented 4 years ago

We are a handful of developers working on a multi-tenancy solution, and this has quickly become an issue. Each tenant has their own database with a specific user.

Creating new connections or establishing and saving a connection for each request feels expensive. Is there another workaround for this until it's added in the mongoose library?

Thanks in advance!

vkarpov15 commented 4 years ago

Creating new connections for each tenant is generally the way to go. Switching on each request using useDb() is not a good way to implement multi-tenant: you may switch databases in the middle of a multi-request operation like populate(). That makes useDb() risky for multi-tenant unless you implement queuing.

linuscarlstrom commented 4 years ago

Cool cool, we'll keep our approach as is then, thanks for the response 👍

vkarpov15 commented 4 years ago

I took a closer look and unfortunately this is not possible. The MongoDB Node.js driver deprecated support for additional authenticate() calls in 2017. So there's no way for Mongoose to support different auth credentials on the same connection pool.

vkarpov15 commented 4 years ago

In order to connect to different databases with different authentication requirements, you need to use multiple connections.

darinrogers commented 10 months ago

@vkarpov15 What if you connect to one database with one set of credentials, but then try to useDb to another database which happens to have a user with same credentials? I believe that even with the same credentials, they are different users. At the command line, I need to call the auth method. But it seems like there's no way to do this from Mongoose? Is a multi-tenant architecture only possible if you don't use authentication?

vkarpov15 commented 10 months ago

@darinrogers Mongoose's docs on multi-tenant connections describe 2 patterns for multi tenancy: 1) shared connection pool using useDb(), 2) separate connection pool per tenant. Pattern (1) is not possible when you need to authenticate as different users for different databases, because the MongoDB server does not support authenticating as multiple users on the same connection pool. But there's no problem with using pattern (2).

darinrogers commented 10 months ago

@vkarpov15 The problem we have is we've got many services, each of which talks to many (and an increasing number of) tenants. And our cluster only allows so many connections, so we quickly run out. I think our long-term solution will be an architectural change, where all or most tenant data goes through one or a few services. But that's beyond the scope of this thread. I was just curious if there were alternatives to username/password that would work with useDb, but it sounds like not. It sounds like any authentication switches are disallowed.

vkarpov15 commented 10 months ago

Yeah, unfortunately there's no way to make useDb() work with multiple authentications, and there's nothing Mongoose can do about it unless the MongoDB server adds support for multiple auth on the same connection.

One potential alternative is to cap the number of sockets per connection: the MongoDB Node driver allows up to 100 sockets per connection by default. You can reduce that with the maxPoolSize option. Would that help?

darinrogers commented 10 months ago

That's what we're doing and it does help. It prevents us from hitting a connection limit. But now, each service/tenant has a small number of sockets per connection and it's noticeably slowing things down. And this doesn't scale well. So I think an architectural change is in order.