please help me finding correct solution in the following situation.
I am developing ios app with swift which will use Firebase as a backend.
Users should be able to login into firebase with email/password or/and with facebook. Maybe google will be added later.
It is important for me to have one firebase account for each real user as user will have reward points and it won't make sense if on one devise(with email login) he will have X points and on other device(with facebook) he will have different points.
Here is code which I am using to login with email:
//EMAIL REGISTER
@IBAction func registerAction(_ sender: Any) {
if self.emailTextField.text == "" || self.passwordTextField.text == "" {
Print( "Please enter email and password.")
} else {
FIRAuth.auth()?.createUser(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!, completion: { (user, error) in
if error == nil {
self.logoutButton.isHidden = false
self.usernameLabel.text = user!.email
self.emailTextField.text = ""
self.passwordTextField.text = ""
} else {
Print("\((error?.localizedDescription)!)")
}
} )
}
}
//EMAIL LOGIN
@IBAction func loginAction(_ sender: Any) {
if self.emailTextField.text == "" || self.passwordTextField.text == "" {
print( "Please enter email and password.")
} else {
FIRAuth.auth()?.signIn(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!, completion: { (user, error) in
if error == nil {
self.logoutButton.isHidden = false
self.usernameLabel.text = user!.email
self.emailTextField.text = ""
self.passwordTextField.text = ""
} else {
Print("\((error?.localizedDescription)!)")
}
})
}
}
Here is code which I am using to login with facebook:
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
self.fbLoginButton.isHidden = true
if error != nil {
self.fbLoginButton.isHidden = false
print(error.localizedDescription)
return
} else if (result.isCancelled) {
print("canceled")
self.fbLoginButton.isHidden = false
} else {
let credential = FIRFacebookAuthProvider.credential(withAccessToken: FBSDKAccessToken.current().tokenString)
FIRAuth.auth()?.signIn(with: credential) { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
}
}
}
Both methods work fine, but they create two separate accounts.
It is set up to allow multiple users with the same email in settings:
and I end up with the following result:
Obviously I want these two accounts to be merged automatically.
Documentation describes the way how to link auth providers, but user should be logged in with one method and only after that it will be possible to link accounts.
linkWithCredential
method is used if you already have the oauth credential. In case user was created on one device with email it wont work if he will decide to login again on other device with facebook.
After loggin in with any of these ways the FIRAuth.auth()?.addStateDidChangeListener
service is showing second view controller where I am working with database.
override func viewDidLoad() { super.viewDidLoad()
let user = FIRAuth.auth()?.currentUser
let dat = user?.providerData
let email = user?.providerData[0].email
let name = user?.displayName
if email != nil {
self.ref.child("user_profile").child("\(user!.uid)/email").setValue(email)
}
if name != {
self.ref.child("user_profile").child("\(user!.uid)/name").setValue(name)
}
}
Let say we loggin with facebook, maybe it is possible to find UID of user with same email and run updates? Not very good idea in case there are a lot of users.
Other idea is to use email as id like this:
self.ref.child("user_profile").child("\(email)/name").setValue(name)
Not sure if it is a good option?
thanks for your replies.
How to sign in a user from different device after he signed in using he's email and password on the first device without anonymous users.
After creating the user you need to save the email and password to
NSUbiquitousKeyValueStore
this way the other device will have access to email and password because you will need to sign in the user first before linking their account to Facebook as you will see below.In FB console
1. Account Email address settings:Prevent creation of multiple accounts with the same email address This way the account doesn't get created again if the user already signed in with email address.
2.If the user choose email address as first login:
After you have signed in the user with Facebook and have fb's token: Usually inside the function's listener of
FBSDKAccessTokenDidChange
Notification, you sign in the user with Firebase with Facebook's token.Since the user already have an account with this email address which he's now trying to sign in with Facebook, so an error will occurs: as you see in step 4, now you need to sign in the user before you link is account to Facebook:
func linkAccountWihtFacebook(){
This way you will have the following result in Firebase console:
Firebase documentation: https://firebase.google.com/docs/auth/ios/account-linking