Multiple AWS Cognito Federated Identities (e.g. Facebook and Google logins for the same email) can be merged into a single identity by passing both logins in the Cognito call. But knowing that I can merge identities doesn’t answer whether I should merge identities.
What are the pros and cons of merging identities vs. keeping them separate? (We store user profiles in our own database; we don’t use Cognito User Pools. If we don’t merge identities, then our back-end database would store the mapping of each identity ID to the correct user ID in our back-end database.)
Here’s the current workflow of the app when the same user tries to auth using both Facebook and Google:
- On the client (it’s a web app), a new user clicks Login and chooses to log in using Facebook.
- The client code logs the user into Cognito Federated Identities and obtains new a federated identity ID that is authorized to call our AWS Lambda functions.
- The client calls our
getOrCreateUserProfile
Lambda function which uses the Cognito Identity ID as a key to see if that Cognito identity is already associated with a user. - Because no other users with this identity ID are found in our database, and because no other user has this email address (because it’s a brand-new user), then our Lambda function will create a new user profile in our database and return the profile back to the user.
- At some point later, the user tries to log in (on the same device or on another device) using Google.
- A new Federated Identity is created for this Google identity.
- Our
getOrCreateUserProfile
Lambda function can’t find an existing user matching this Identity ID, but does find another user with the same email address.
At this point we have three options:
- A) Return an error to the user, e.g. "Please log in using your Facebook account". This is the current behavior that we want to change.
- B) Merge the identities by requiring the user to log in using Facebook too, and then pass both identities to Cognito which will merge them. See https://stackoverflow.com/a/45045123/126352
- C) Add a mapping row in our back-end database to map the new identity to user’s existing user profile. Now this user will have two Federated Identities: one using the Facebook provider, one using the Google provider.
What are the pros and cons of option (B) vs. option (C)? Below is a starting point for this comparison. What pros/cons am I missing?
Merge Identities
- Pro
- Simpler/faster lookups because there’s only one Identity ID per user that must be indexed on the back end
- I assume this is the most secure solution?
- Con
- The merging process itself seems complex and error-prone. For example, after merging, if the new ID "wins" the merge, then we’ll need to replace the old ID with the new one in the user profile… and if something goes wrong during that process we might be left in an unrecoverable state where Cognito only knows about the new (merged) ID but our database only knows about the old one.
- More complex UX where user must log in (albeit only once) to both Facebook and Google accounts in the same session in order to link those accounts.
- Any later changes to linking must go through Cognito API
Keep Separate
- Pro
- Simpler UX: we can link social accounts by matching the email addresses; no need for both logins in one session
- Can control linking solely within our back-end database, which should make it easier to build admin tools that add/remove/change identity->user-profile links as opposed to having to call Cognito’s API to perform these actions.
- No risk of Cognito getting out of sync with our back-end DB. If linking fails, the user can simply retry.
- Con
- Need a many:1 index to map Identity ID -> User Profile, instead of a single indexed column
- Is this a less secure solution? If so, why?
- Is this more costly in AWS charges? If so, why?
I’m leaning towards the "Keep Separate" solution because it seems simpler to implement (no extra UX workflow) and easier for users (for the same reason: no new UX workflow). Is this a mistake?
2
Answers
It is very difficult give you an answer, I think you have already provided the main pros and cons of all possible solutions.
I will only try to clarify only some of them, which I consider key to choose one solution and not the other.
First of all, indicate that I would also prefer the keep separate solution. Let me try to explain why.
From a UX point of view, it is clear that the keep separate solution is a much better approach for the user. To merge the identities of the different social providers, the user needs to log in with them, in a more complex application sign up workflow. But this process is motivated only for a technical decision, and it will not provide any actual benefit to the user.
I think a much better and simpler solution is to just include a mapping between each identity and the associated email as you propose in the keep separate solution, and let the user log in into the application with the provider that he or she prefer, transparently "merging", in your application code, all this sign in mechanisms. This requirement could easily be achieved regardless of the type of underlying information system you are using to store the user information.
Please, also think in what will happen if your need to include in your application another different social provider and an already existing user wants to log in into your application with that new provider: how will the identities be merged? Should the user repeat the process again?
In addition, the identity merge functionality is something very specific to Cognito. If you adopt the merge solution, you are taking the risk of tightly coupling your application with AWS and AWS Cognito. If you need to move your application to another cloud provider or on-premises deployment, you maybe won’t have the ability to make such an association. Again, the mapping between some kind of identity information and your internal user model adopted in the keep separate solution seems like a much better and portable approach.
The risk of not being in sync with Cognito could be another great problem. What will be the recover mechanism?
The only real downside to the keep separate solution might be that you will likely incur more charges from AWS. As you can see in the product pricing documentation, AWS will charge you for every monthly active user (MAUs). If you have more identities, as with the keep separate solution, it is probably that there will be more MAUs and you may incur higher costs. In any case, these costs will not be much higher and, nevertheless, I believe that the advantages that the keep separate solution offers will compensate this minimum price increase.
Finally, I don’t think the keep separate solution is a less secure option: although it seems you are federating identities to allow your users to interact with AWS services, the same policy and role assumption will apply regardless of the actual identity the user provides.
I think the merge solution will be best suited for scenarios where you have federation and need to uniquely identify a user regardless of how they authenticate, but probably to enforce some kind of policy (custom role assumption etc) related with the use of AWS resources based only on those specific identities, and probably, when you do not have an application backend available.
Regardless of the solution finally adopted, a key success factor will be to maintain an user model and associated logic as independent as possible of the mechanisms used to authenticate the user: the keep separate solution also helps to think in that way.
From a user perspective it can feel quite confusing and uneasy to log in through the second provider only to find that they have none of their previous content. From this point of view I think merging would be the best end goal.
Now from a technical perspective I had a swing at this and found out that it’s quite a hassle. I managed to merge identities when user first logs in with email and then with social but not the other way around. I guess the only option is to have a pre-signup lambda trigger that checks the DB for previous logins on that particular email and ask user to login on those too to do the merge or just continue login on the existing. This is easier to say than to do if there is more than one pre-existing login though.
On the question of who "wins" the merge, It’s always the pre-existing one. Also in the end it doesn’t matter since all logins will be using the same cognito federated ID through the calls.