fix: find linked account from authentication error and link it (#2662)

Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
Jesvin Jose
2022-10-04 01:08:00 +05:30
committed by GitHub
parent 3140859993
commit 3c17a14bd3
2 changed files with 35 additions and 68 deletions

View File

@@ -129,7 +129,6 @@ import {
setProviderInfo, setProviderInfo,
currentUser$, currentUser$,
signInWithEmail, signInWithEmail,
linkWithFBCredential,
linkWithFBCredentialFromAuthError, linkWithFBCredentialFromAuthError,
getGithubCredentialFromResult, getGithubCredentialFromResult,
} from "~/helpers/fb/auth" } from "~/helpers/fb/auth"
@@ -191,32 +190,11 @@ export default defineComponent({
this.showLoginSuccess() this.showLoginSuccess()
} catch (e) { } catch (e) {
console.error(e) console.error(e)
// An error happened. /*
if ( A auth/account-exists-with-different-credential Firebase error wont happen between Google and any other providers
(e as any).code === "auth/account-exists-with-different-credential" Seems Google account overwrites accounts of other providers https://github.com/firebase/firebase-android-sdk/issues/25
) { */
// Step 2. this.toast.error(`${this.t("error.something_went_wrong")}`)
// User's email already exists.
// The pending Google credential.
const pendingCred = (e as any).credential
this.toast.info(`${this.t("auth.account_exists")}`, {
duration: 0,
closeOnSwipe: false,
action: {
text: `${this.t("action.yes")}`,
onClick: async (_, toastObject) => {
const { user } = await signInUserWithGithub()
await linkWithFBCredential(user, pendingCred)
this.showLoginSuccess()
toastObject.goAway(0)
},
},
})
} else {
this.toast.error(`${this.t("error.something_went_wrong")}`)
}
} }
this.signingInWithGoogle = false this.signingInWithGoogle = false
@@ -228,27 +206,22 @@ export default defineComponent({
const result = await signInUserWithGithub() const result = await signInUserWithGithub()
const credential = getGithubCredentialFromResult(result)! const credential = getGithubCredentialFromResult(result)!
const token = credential.accessToken const token = credential.accessToken
setProviderInfo(result.providerId!, token!) setProviderInfo(result.providerId!, token!)
this.showLoginSuccess() this.showLoginSuccess()
} catch (e) { } catch (e) {
console.error(e) console.error(e)
// An error happened. // This user's email is already present in Firebase but with other providers, namely Google or Microsoft
if ( if (
(e as any).code === "auth/account-exists-with-different-credential" (e as any).code === "auth/account-exists-with-different-credential"
) { ) {
// Step 2.
// User's email already exists.
this.toast.info(`${this.t("auth.account_exists")}`, { this.toast.info(`${this.t("auth.account_exists")}`, {
duration: 0, duration: 0,
closeOnSwipe: false, closeOnSwipe: false,
action: { action: {
text: `${this.t("action.yes")}`, text: `${this.t("action.yes")}`,
onClick: async (_, toastObject) => { onClick: async (_, toastObject) => {
const { user } = await signInUserWithGoogle() await linkWithFBCredentialFromAuthError(e)
await linkWithFBCredentialFromAuthError(user, e)
this.showLoginSuccess() this.showLoginSuccess()
toastObject.goAway(0) toastObject.goAway(0)
@@ -270,32 +243,15 @@ export default defineComponent({
this.showLoginSuccess() this.showLoginSuccess()
} catch (e) { } catch (e) {
console.error(e) console.error(e)
// An error happened. /*
if ( A auth/account-exists-with-different-credential Firebase error wont happen between MS with Google or Github
(e as any).code === "auth/account-exists-with-different-credential" If a Github account exists and user then logs in with MS email we get a "Something went wrong toast" and console errors and MS replaces GH as only provider.
) { The error messages are as follows:
// Step 2. FirebaseError: Firebase: Error (auth/popup-closed-by-user).
// User's email already exists. @firebase/auth: Auth (9.6.11): INTERNAL ASSERTION FAILED: Pending promise was never set
// The pending Microsoft credential. They may be related to https://github.com/firebase/firebaseui-web/issues/947
const pendingCred = (e as any).credential */
this.toast.info(`${this.t("auth.account_exists")}`, { this.toast.error(`${this.t("error.something_went_wrong")}`)
duration: 0,
closeOnSwipe: false,
action: {
text: `${this.t("action.yes")}`,
onClick: async (_, toastObject) => {
const { user } = await signInUserWithGithub()
await linkWithFBCredential(user, pendingCred)
this.showLoginSuccess()
toastObject.goAway(0)
},
},
})
} else {
this.toast.error(`${this.t("error.something_went_wrong")}`)
}
} }
this.signingInWithMicrosoft = false this.signingInWithMicrosoft = false

View File

@@ -237,19 +237,30 @@ export async function linkWithFBCredential(
/** /**
* Links account with another account given in a auth/account-exists-with-different-credential error * Links account with another account given in a auth/account-exists-with-different-credential error
* *
* @param user - User who has the errors
*
* @param error - Error caught after trying to login * @param error - Error caught after trying to login
* *
* @returns Promise of UserCredential * @returns Promise of UserCredential
*/ */
export async function linkWithFBCredentialFromAuthError( export async function linkWithFBCredentialFromAuthError(error: unknown) {
user: User, // credential is not null since this function is called after an auth/account-exists-with-different-credential error, ie credentials actually exist
error: unknown
) {
// Marked as not null since this function is supposed to be called after an auth/account-exists-with-different-credential error, ie credentials actually exist
const credentials = OAuthProvider.credentialFromError(error as AuthError)! const credentials = OAuthProvider.credentialFromError(error as AuthError)!
return await linkWithCredential(user, credentials)
const otherLinkedProviders = (
await getSignInMethodsForEmail((error as AuthError).customData.email!)
).filter((providerId) => credentials.providerId !== providerId)
let user: User | null = null
if (otherLinkedProviders.indexOf("google.com") >= -1) {
user = (await signInUserWithGoogle()).user
} else if (otherLinkedProviders.indexOf("github.com") >= -1) {
user = (await signInUserWithGithub()).user
} else if (otherLinkedProviders.indexOf("microsoft.com") >= -1) {
user = (await signInUserWithMicrosoft()).user
}
// user is not null since going through each provider will return a user
return await linkWithCredential(user!, credentials)
} }
/** /**