Auth: How to solve user credential merge conflict?
Hi,
Anyone can please help me to solve merge conflicts when link account. How to link account when the credentials already have an existing account.
Thanks.
Hi @initfusion, you can start from this doc, which introduces how to link multiple auth providers to one account in Unity. You can also find related docs for other platforms under iOS / Android / Web and C++.
Hope this helps.
Hi @cynthiajoan, this doc is not enough for solving conflicts. Because the credentials which I linking is having an existing account so we have to delete the new account first. After that, we can link.
I have followed the doc https://firebase.google.com/docs/auth/web/account-linking
// Get reference to the currently signed-in user
var prevUser = auth.currentUser;
// Sign in user with another account
auth.signInWithCredential(credential).then(function(user) {
console.log("Sign In Success", user);
var currentUser = user;
// Merge prevUser and currentUser data stored in Firebase.
// Note: How you handle this is specific to your application
// After data is migrated delete the duplicate user
return user.delete().then(function() {
// Link the OAuth Credential to original account
return prevUser.linkWithCredential(credential);
}).then(function() {
// Sign in with the newly linked credential
return auth.signInWithCredential(credential);
});
}).catch(function(error) {
console.log("Sign In Error", error);
});
But the above code is in javascript.
In c# how to store prevUser? when I have signInWithCredantial I am lost the current user.
Hi @initfusion, if I understand correctly, in Unity/C#, we have this example maybe can solve your problem: Unity account linking
// Gather data for the currently signed in User. string currentUserId = auth.CurrentUser.UserId; string currentEmail = auth.CurrentUser.Email; string currentDisplayName = auth.CurrentUser.DisplayName; System.Uri currentPhotoUrl = auth.CurrentUser.PhotoUrl;
// Sign in with the new credentials. auth.SignInWithCredentialAsync(credential).ContinueWith(task => { if (task.IsCanceled) { Debug.LogError("SignInWithCredentialAsync was canceled."); return; } if (task.IsFaulted) { Debug.LogError("SignInWithCredentialAsync encountered an error: " + task.Exception); return; }
Firebase.Auth.FirebaseUser newUser = task.Result; Debug.LogFormat("User signed in successfully: {0} ({1})", newUser.DisplayName, newUser.UserId);
// TODO: Merge app specific details using the newUser and values from the // previous user, saved above. });
You can grab prevUser by auth.CurrentUser before signInWithCredantial.
Let me know if that works for you.
Hi @cynthiajoan Yes, I have done that way but after doing signInWithCredantial the prevUser which I have grabbed previously is also changed to the new user.
I think its sync new user to all its existing user instances.
Hi This is I am trying
var credential = EmailAuthProvider.GetCredential(email, password);
auth.CurrentUser.LinkWithCredentialAsync(credential).ContinueWithOnMainThread(task =>
{
if (task.IsCanceled)
{
Debug.Log("Cancel");
}
if (task.IsFaulted)
{
Debug.Log("Faulted");
var currentUser = auth.CurrentUser;
otherAuth.SignInWithCredentialAsync(credential).ContinueWithOnMainThread(linkTask =>
{
Debug.Log("Current: " + currentUser.UserId);
Debug.Log("New: " + linkTask.Result.UserId);
// Here both current and new have the same user.
});
}
if (task.IsCompleted)
{
Debug.Log("Completed");
}
});
HI @initfusion ,
as per @cynthiajoan suggestion, have you tried caching the individual fields you need before executing the SignInWithCredentialAsync? The JavaScript and Unity APIs will be slightly different.
--Patrick
Hi @patm1987,
Yes, I can cache the individual fields but I need the previous user to link the user. Without a previous user, I can't call the LinkWithCredantials.

With the Unity API, you just need the credential of the account you want to link with the current one (ie: if your continuation from LinkWithCredentialAsync succeeds, you should have linked accounts). You can get more information here:
https://firebase.google.com/docs/reference/unity/class/firebase/auth/firebase-user#linkandretrievedatawithcredentialasync
Let me know if it's not the case, but you should be able to verify that the merger worked in your firebase authentication dashboard (in console.firebase.google.com).
Hi @patm1987
Yes, it's not the case, Link account is working properly when there is no error when link. But if there is an error (ie: if the credential which is I am going to merge is already having an account).
In that case, I have to delete the existing account. for delete existing account I have to SignIn so I can get the user and using that user I can delete.
if there is another way to solve merge conflicts then let me know.
Let me know if you still not understand my problem.
@initfusion it looks like you've found a problem with both the C++ and Unity SDKs here. You're right that it's not currently possible to copy the FirebaseUser object in the C# API which is an issue in the case you've described where you want to:
- Cache the current user's auth token
- Attempt to sign in with credentials (e.g email / password) and if that results in a different user, delete the other user's account.
- Link the credentials (email / password) with the current user's account
However, I think it's possible to do this with multiple FirebaseApp objects instead:
- Create a secondary FirebaseApp object and a FirebaseAuth object from that (e.g
otherAuth) - Then if credential linking fails with
FirebaseAuth.DefaultInstance.CurrentUser, sign-in tootherAuthwith the credentials - Delete
otherAuth.CurrentUser - Try linking credentials on
FirebaseAuth.DefaultInstance.CurrentUseragain
Hi @stewartmiles
Thanks for understanding my problem. I was also tried with multiple Firebase objects but still not able to get or cache the current user's auth token.
Here is my code
otherAuth = FirebaseAuth.GetAuth(FirebaseApp.Create(AppOptions.LoadFromJsonConfig(conf.text)));
Now I am trying this but still, both are the same.
var credential = EmailAuthProvider.GetCredential(email, password);
auth.CurrentUser.LinkAndRetrieveDataWithCredentialAsync(credential).ContinueWithOnMainThread(task =>
{
if (task.IsCanceled)
{
Debug.Log("Cancel");
}
if (task.IsFaulted)
{
Debug.Log("Faulted");
otherAuth.SignInWithCredentialAsync(credential).ContinueWithOnMainThread(linkTask =>
{
Debug.Log("Current: " + auth.CurrentUser.UserId);
Debug.Log("New: " + otherAuth.CurrentUser.UserId);
// Here both current and new have same user..
});
}
if (task.IsCompleted)
{
Debug.Log("Completed");
}
});
FirebaseApp.Create() will create the default app, you need to create a named secondary app using FirebaseApp.Create(options, name) see https://firebase.google.com/docs/reference/unity/class/firebase/firebase-app#class_firebase_1_1_firebase_app_1a39a702e1912ab6b708600b03bd955f4d
Here's an example: https://github.com/firebase/quickstart-unity/blob/master/auth/testapp/Assets/Firebase/Sample/Auth/UIHandler.cs#L97
Hi @stewartmiles
Thank you very much, using a secondary app solve my problem in all the methods except phone auth.
Now I am facing a new issue when link phone credentials. If phone auth link fails then I have used the same way to solve merge conflict.
- First, I copy the credentials of phone auth after auto verification completed
var phoneAuthProvider = PhoneAuthProvider.GetInstance(_auth);
phoneAuthProvider.VerifyPhoneNumber(phoneNumber, PhoneAuthTimeoutMs, null,
cred =>
{
_phoneAuthCredentials = cred;
},
- After that I linked the credentials to current user.
_user.LinkWithCredentialAsync(_phoneAuthCredentials).ContinueWithOnMainThread(HandleLinkWithUser);
- Now I get merge error
- After that, if I sign with that credentials I am getting "Phone auth code expire" error.
_otherAuth.SignInWithCredentialAsync(_phoneAuthCredentials).ContinueWithOnMainThread(HandleMergeConflict);
After deleting the other phone auth account could you run through the VerifyPhoneNumber() step again ? I know it's a little irritating for the user but I'm sure you can pop up a message explaining what happened (e.g there was a duplicate account).
Hi @stewartmiles
This is not a proper way, because I need to VerifyPhoneNumber() 3 times.
- First, When linking the account first time.
- Second, When sigh in and delete the account
- Third, When linking again.
It's very irritating for the user. My testing phone numbers are work but others do not work.
@initfusion I see what you mean, that is a pain. We'll try to get a fix out soon.
Hi @stewartmiles,
May I know ETA for this issue?
@initfusion we don't have a timeline for the change yet. I took a quick look at it last week and it's a non-trivial change to the way we store user data at the moment in the C++ SDK.