The answer is not that simple, so first, we’ll split the question into smaller parts and then we’ll provide the answer in the conclusion.
1. Build a fully developed system for creating user accounts and allowing the users to sign up using their email addresses or external identity providers such as Facebook and Google.
2. Make the system deployable and easily maintainable on multiple domains and at the same time keep the users from different domains in one single database. This implies that a user with one email address will be considered a different user on two different domains.
We considered building a user access management system from scratch. This means that we would have to manually implement all the features listed below:
Luckily, we did some digging around and we learned that Amazon Cognito can provide all of the previously mentioned features with just a few clicks.
Amazon Cognito is a service that provides simple and secure user management. It supports sign-in with identity providers such as Facebook and Google and it’s a cost-effective solution.
Amazon Cognito is really simple to set up and use. You simply request the appropriate Cognito User Pool to retrieve the tokens, and you use those tokens to access your application. In our case, since we use API Gateway, we set up the Cognito User Pool as an authorizer in each method request that leads to the private area of the application only accessible if you are a logged-in user. A similar example is presented in the visual below:
The complete solution includes a microservice, deployed on ECS. The microservice is managing the creation of users in the appropriate Cognito User Pool, returning login tokens and personal data for the authenticated user.
When a user creates an account or logs in, the domain’s attributes are forwarded together with the login/registration data. Next, the service issues the authorization tokens from the appropriate Cognito User Pool. In front of the microservice, we set up two API Gateways. One of them serves the publicly accessible APIs like the registration and the login API which do not require authorized access. The other API Gateway has Cognito User Pool set as an authorizer.
And how did we solve the multi-tenancy problem?
If we opted for a single-user pool with all users in one place, we would have allowed username and password login instead of email address and password. This would also prevent us from allowing login through federated identity providers. To be able to provide federated login then we would have to rewrite a large amount of custom logic.
To overcome these possible setbacks, we created and customized a separate Cognito User Pool for each domain. In the end, we still save the users in one single database, but we have different user pools per domain.
Using Amazon Cognito for user authentication is much easier and more efficient than building a custom authentication service from scratch. And most importantly, you don’t get to worry about the security or encryption of the data.
Having multiple domains into one single user pool wasn’t possible in our case since we wanted the login to be only with an email address or through Facebook / Google. Taking this into consideration, we opted to go with multiple user pools.
And last but not least, to cut down on creating multiple resources and doing the additional maintenance work, we decided to have one API Gateway per environment with multiple stages deployed for each domain.