The last section walked you through implementing social logins for Google, Facebook, and Twitter to being able to sign up/in with a email/password combination. However, since you have enabled multiple accounts for one email address, there is more than one account associated to your email, which can lead to bugs for your service/product. Imagine a user signs in with Google, buys a ebook on your website, is able to download the book as signed in user, and then signs out again. The next sign-in with the email/password combination wonât show the e-book anymore. This is because the user has two accounts on your website. While one account is associated with Google, the other one is associated with the email/password combination.
To walk through this scenario, take one of your social accounts (Google, Facebook, Twitter) and log into the Firebase in React application. Check the account page and copy the email address that is associated to your social account. Log out and log in again with your email/password combination, using the same email as for your social login. Itâs possible because we enabled multiple accounts for the same email address in the Firebase dashboard. When you check the account page again, you should see the same email as when you logged in with the social account. Now head to your Firebase dashboard and check the âAuthenticationâ tab. You should find two accounts associated to the same email you used before. The same applies for the âDatabaseâ tab.
In this section, we want to prevent this behavior by using only one email address per user, while still being able to sign-in via email/password, Google, Facebook or Twitter. It shouldnât matter which sign-in you take, as the account should be the same. Thatâs where the linking of all the social accounts comes in.
Before we get started, head to the Authentication and Database tabs on your Firebase dashboard and delete the user you used with your personal email address. We will use this email address later, except this time it will end up once in both tabs for one account. First, disable the setting on your Firebase dashboard that encourages email addresses associated to more than one account.
We will prevent the user from signing in with another account when there is already an account associated to this email address. A message should point the user to the account page to link all the social accounts and the email/password account with each other instead. Letâs show the user a custom error message for the sign up page. First, extract the error code and the custom message as variables:
Next, show the custom error message when the error code shows up. Thatâs because we prevent more than one email address for one account:
Repeat this for the other social logins (Facebook, Twitter) as well. If a user signs in with one of the social logins, but there is already an account in the system with this email address, the custom error message shows up. The user has to log in with the correct sign-in method and link all other desired social accounts to this account on the account page. We will add this feature later in the account page, but before this, we need to show a similar custom error message for the sign up page as well. The user might use a social login first and later attempt to sign up with an email address (email/password sign up) that has been used by the social login already.
Use the custom error message when the error code happens on sign-up:
Now users can use the same email address for different sign-in methods. Next, letâs head to the account page, where weâll create an area to manage and activate/deactivate all the sign-in methods (social sign-ins, email/password sign-in). Introduce all available sign-in methods and their optional providers (see Firebase class) as list of objects:
Now implement the new component and render all available sign-in methods as buttons which are doing nothing:
Remember to make the Firebase instance available to the component, because we need to use it in the next step:
Then, fetch all active sign-in methods for the userâs email address. Firebase has an API for it:
Next, differentiate between active sign-in methods and the remaining sign-in methods not in the list of fetched sign-in methods. You can show an error message with a conditional rendering as well:
While all available sign-in methods are displayed, they differentiate between active and non-active. The active methods can be deactivated. On the other hand, sign-in methods that are available but not used by the user can be linked instead to make them active. We will implement both details in the next step:
Extract the fetch method, because we will use it after we linked (activated) or unlinked (deactivated) sign-in methods. Then the new class methods can be used by the buttons:
Also, we added an improvement to avoid getting locked out of the application. If only one sign-in method is left as active, disable all deactivation buttons because there needs to be at least one sign-in method. Now letâs implement the class methods for linking and unlinking accounts:
Finally we are able to link and unlink accounts. Afterward, all active sign-in methods are fetched again. Thatâs why we have extracted this class method from the componentDidMount() lifecycle method before, which is reusable now. The linking of the sign-in methods should work for Google, Facebook and Twitter now. However, it doesnât work for the email/password combination yet, because this one isnât done by a simple button click. If the user has only active social sign-in methods but no email/password sign-in method, an email/password combination must be provided; then it is possible to link this sign-in method to the other social sign-in methods.
First, extract the social sign-in methods to its own component and add a conditional rendering for the password sign-in method:
The DefaultLoginToggle component will use a different onLink handler than the SocialLoginToggle component, but the onUnlink stays the same. We will implement DefaultLoginToggle component and its missing handler in a moment, but first letâs extract the SocialLoginToggle component:
The implementation details didnât change, but the component is standalone now. Next, letâs implement the other component for the email/password sign-in. When this sign-in method is activated, itâs sufficient to render only a button similar to the social sign-in methods to unlink (deactivate) this sign-in method. If this sign-in method isnât activated, you need to retrieve the userâs desired email and password combination to link it as account to the other social accounts. Itâs very similar to our sign up form then:
Next, letâs implement the handler in the parent component for the default sign-in via email/password. It receives a password from the child component, which is added to the authenticated userâs email address:
The Firebase API is not too elegant here, but itâs good to know that it creates a credential from the userâs email and desired password. Afterward, it links it to the other accounts. Then all active sign-in methods are fetched again to keep everything updated.
Previously, when we set up our Firebase class, we overrode its auth property with app.auth() . However, to create the credential from the email and password in the component, we need access to the Firebase internal auth , which has the EmailAuthProvider property, so we reference it before we override it with app.auth() in the next lines.
Now you can link and unlink different sign-in methods using only one account and email address.