Skip to main content
RapidDev - Software Development Agency
firebase-tutorial

How to Link Multiple Auth Providers in Firebase

Firebase lets users link multiple sign-in methods to a single account using linkWithPopup, linkWithCredential, or linkWithPhoneNumber. This means a user who signed up with email can later add Google or phone sign-in. The key challenge is handling the auth/account-exists-with-different-credential error, which fires when a user tries to sign in with a provider that uses an email already registered under a different provider. Use fetchSignInMethodsForEmail to detect this and guide the user through linking.

What you'll learn

  • How to link OAuth, email, and phone providers to one account
  • How to handle the account-exists-with-different-credential error
  • How to unlink a provider from an existing account
  • How to check which providers are linked to a user
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate7 min read15-20 minFirebase JS SDK v9+, all plansMarch 2026RapidDev Engineering Team
TL;DR

Firebase lets users link multiple sign-in methods to a single account using linkWithPopup, linkWithCredential, or linkWithPhoneNumber. This means a user who signed up with email can later add Google or phone sign-in. The key challenge is handling the auth/account-exists-with-different-credential error, which fires when a user tries to sign in with a provider that uses an email already registered under a different provider. Use fetchSignInMethodsForEmail to detect this and guide the user through linking.

Linking Multiple Auth Providers to One Firebase Account

Users expect to sign in with any method and reach the same account. Firebase supports linking multiple auth providers (Google, GitHub, email, phone) to a single user record. This tutorial covers the linking flow, the most common error scenario when two providers share the same email, and how to build a UI that shows linked providers and lets users manage them.

Prerequisites

  • A Firebase project with at least two auth providers enabled
  • Firebase JS SDK v9+ installed in your project
  • A signed-in user to link additional providers to
  • Basic understanding of Firebase Auth and OAuth flows

Step-by-step guide

1

Check which providers are already linked

Before linking a new provider, inspect the current user's providerData array. Each entry represents a linked provider and includes the providerId (e.g. 'google.com', 'password', 'phone'), the email or phone number, and the display name. This lets you show which methods are active and prevent trying to link a provider that is already connected.

typescript
1import { getAuth } from 'firebase/auth'
2
3const auth = getAuth()
4
5function getLinkedProviders() {
6 const user = auth.currentUser
7 if (!user) return []
8
9 return user.providerData.map((provider) => ({
10 id: provider.providerId,
11 email: provider.email,
12 phone: provider.phoneNumber,
13 name: provider.displayName,
14 }))
15}
16
17// Example output:
18// [{ id: 'password', email: 'user@example.com', ... },
19// { id: 'google.com', email: 'user@gmail.com', ... }]

Expected result: An array of linked providers for the current user, which you can use to render toggle buttons in your settings UI.

2

Link an OAuth provider with linkWithPopup

To add Google, GitHub, or another OAuth provider to an existing account, create a provider instance and call linkWithPopup on the current user. This opens the OAuth consent screen. On success, the provider is permanently linked and the user can sign in with either method. If the provider's email is already used by a different Firebase account, this will throw auth/credential-already-in-use.

typescript
1import { GoogleAuthProvider, linkWithPopup } from 'firebase/auth'
2
3async function linkGoogle() {
4 const user = auth.currentUser
5 if (!user) throw new Error('Must be signed in')
6
7 const provider = new GoogleAuthProvider()
8
9 try {
10 const result = await linkWithPopup(user, provider)
11 console.log('Google linked:', result.user.providerData)
12 } catch (error: any) {
13 if (error.code === 'auth/credential-already-in-use') {
14 console.error('This Google account is already linked to another user.')
15 } else if (error.code === 'auth/provider-already-linked') {
16 console.error('Google is already linked to this account.')
17 }
18 throw error
19 }
20}

Expected result: The Google provider appears in the user's providerData array and the user can sign in with Google or their original method.

3

Handle account-exists-with-different-credential

When a user tries to sign in with a new provider (e.g. GitHub) but the email is already registered under a different provider (e.g. Google), Firebase throws auth/account-exists-with-different-credential. To resolve this, use fetchSignInMethodsForEmail to find the existing provider, sign the user in with that provider, then link the new credential to merge both providers into one account.

typescript
1import {
2 signInWithPopup,
3 GoogleAuthProvider,
4 GithubAuthProvider,
5 fetchSignInMethodsForEmail,
6 linkWithCredential,
7 OAuthProvider,
8} from 'firebase/auth'
9
10async function signInWithGitHub() {
11 const provider = new GithubAuthProvider()
12
13 try {
14 const result = await signInWithPopup(auth, provider)
15 return result.user
16 } catch (error: any) {
17 if (error.code === 'auth/account-exists-with-different-credential') {
18 const email = error.customData?.email
19 const pendingCred = OAuthProvider.credentialFromError(error)
20 if (!email || !pendingCred) throw error
21
22 // Find which provider the email is registered with
23 const methods = await fetchSignInMethodsForEmail(auth, email)
24 console.log('Sign in with', methods[0], 'first, then link GitHub')
25
26 // Sign in with the existing provider (e.g. Google)
27 const googleProvider = new GoogleAuthProvider()
28 const googleResult = await signInWithPopup(auth, googleProvider)
29
30 // Link the pending GitHub credential
31 await linkWithCredential(googleResult.user, pendingCred)
32 console.log('GitHub linked successfully')
33 return googleResult.user
34 }
35 throw error
36 }
37}

Expected result: Both providers are linked to the same account and the user can sign in with either Google or GitHub in the future.

4

Link email/password credentials to an OAuth account

If a user originally signed in with Google and wants to add a password for direct email login, use EmailAuthProvider.credential() and linkWithCredential(). This is useful for users who want a fallback sign-in method or for apps that require a password for sensitive actions.

typescript
1import { EmailAuthProvider, linkWithCredential } from 'firebase/auth'
2
3async function linkEmailPassword(
4 email: string,
5 password: string
6) {
7 const user = auth.currentUser
8 if (!user) throw new Error('Must be signed in')
9
10 const credential = EmailAuthProvider.credential(email, password)
11
12 try {
13 const result = await linkWithCredential(user, credential)
14 console.log('Email/password linked:', result.user.email)
15 } catch (error: any) {
16 if (error.code === 'auth/email-already-in-use') {
17 console.error('This email is already used by another account.')
18 } else if (error.code === 'auth/weak-password') {
19 console.error('Password must be at least 6 characters.')
20 }
21 throw error
22 }
23}

Expected result: The email/password provider is linked and the user can now sign in with either Google or email/password.

5

Unlink a provider from the account

Users may want to remove a linked provider. Call unlink() on the current user with the providerId to remove. Firebase prevents unlinking the last remaining provider — the user must always have at least one sign-in method. Check providerData.length before unlinking to warn the user.

typescript
1import { unlink } from 'firebase/auth'
2
3async function unlinkProvider(providerId: string) {
4 const user = auth.currentUser
5 if (!user) throw new Error('Must be signed in')
6
7 if (user.providerData.length <= 1) {
8 throw new Error('Cannot unlink the only sign-in method')
9 }
10
11 try {
12 const updatedUser = await unlink(user, providerId)
13 console.log('Unlinked', providerId)
14 console.log('Remaining providers:', updatedUser.providerData.map(p => p.providerId))
15 } catch (error: any) {
16 if (error.code === 'auth/no-such-provider') {
17 console.error('This provider is not linked to this account.')
18 }
19 throw error
20 }
21}

Expected result: The specified provider is removed from the user's account. The user can no longer sign in with that method.

Complete working example

auth-provider-linking.ts
1import { initializeApp } from 'firebase/app'
2import {
3 getAuth,
4 GoogleAuthProvider,
5 GithubAuthProvider,
6 EmailAuthProvider,
7 linkWithPopup,
8 linkWithCredential,
9 unlink,
10 fetchSignInMethodsForEmail,
11 OAuthProvider,
12 signInWithPopup,
13 onAuthStateChanged,
14} from 'firebase/auth'
15
16const app = initializeApp({
17 apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY!,
18 authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN!,
19 projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID!,
20})
21
22const auth = getAuth(app)
23
24export function getLinkedProviders() {
25 return auth.currentUser?.providerData.map((p) => p.providerId) ?? []
26}
27
28export async function linkGoogle() {
29 if (!auth.currentUser) throw new Error('Sign in first')
30 return linkWithPopup(auth.currentUser, new GoogleAuthProvider())
31}
32
33export async function linkGitHub() {
34 if (!auth.currentUser) throw new Error('Sign in first')
35 return linkWithPopup(auth.currentUser, new GithubAuthProvider())
36}
37
38export async function linkEmail(email: string, password: string) {
39 if (!auth.currentUser) throw new Error('Sign in first')
40 const cred = EmailAuthProvider.credential(email, password)
41 return linkWithCredential(auth.currentUser, cred)
42}
43
44export async function unlinkProvider(providerId: string) {
45 if (!auth.currentUser) throw new Error('Sign in first')
46 if (auth.currentUser.providerData.length <= 1) {
47 throw new Error('Cannot remove last provider')
48 }
49 return unlink(auth.currentUser, providerId)
50}
51
52export function onAuth(cb: (user: any) => void) {
53 return onAuthStateChanged(auth, cb)
54}

Common mistakes when linkking Multiple Auth Providers in Firebase

Why it's a problem: Trying to link a provider that is already linked, throwing auth/provider-already-linked

How to avoid: Check user.providerData for the providerId before calling linkWithPopup or linkWithCredential.

Why it's a problem: Losing the pending credential during the account-exists-with-different-credential flow when using redirect auth

How to avoid: Store the pending credential in sessionStorage before redirecting to the existing provider's sign-in. Retrieve it after the redirect completes.

Why it's a problem: Allowing the user to unlink their only sign-in method, which locks them out

How to avoid: Check providerData.length before unlinking and disable the unlink button when only one provider remains.

Best practices

  • Always check providerData before linking to avoid auth/provider-already-linked errors
  • Handle auth/account-exists-with-different-credential by guiding the user to sign in with their existing provider first
  • Store pending credentials in sessionStorage during redirect flows to prevent data loss
  • Show users a clear list of linked providers in their account settings
  • Prevent unlinking the last remaining provider to avoid locking users out
  • Use linkWithPopup on desktop and linkWithRedirect on mobile for the best UX
  • After linking or unlinking, call user.reload() to refresh the local user object

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I have a Firebase app where users can sign in with Google, GitHub, or email/password. Show me how to link multiple auth providers to one account using the modular SDK v9. Include handling for the account-exists-with-different-credential error and a way to unlink providers.

Firebase Prompt

Add an account settings panel that shows which auth providers are linked (Google, GitHub, email, phone). Let users link new providers with linkWithPopup and unlink existing ones. Handle the account-exists-with-different-credential error gracefully.

Frequently asked questions

How many auth providers can I link to one Firebase account?

There is no hard limit on the number of providers you can link to a single account. You can link email/password, phone, and multiple OAuth providers (Google, GitHub, Facebook, Apple, etc.) to the same user.

What happens if two users have the same email with different providers?

By default, Firebase blocks sign-in with auth/account-exists-with-different-credential. You should handle this by prompting the user to sign in with their existing provider and then linking the new provider.

Can I link a phone number to an email/password account?

Yes. Use linkWithPhoneNumber on the current user to add phone auth as an additional sign-in method. The Blaze plan is required for phone auth.

Does linking providers merge user data?

No. Linking only merges authentication methods. If the user had data under a separate UID from a different account, you need to manually merge that data in your database.

Can I automatically link accounts with the same email?

Firebase does not automatically link accounts. You must handle the account-exists-with-different-credential error and guide the user through the linking flow. This is a deliberate security measure.

Can RapidDev help implement multi-provider auth linking in my app?

Yes. RapidDev can build a complete multi-provider authentication system with account linking, conflict resolution, and a settings UI for managing connected providers.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.