FirebaseAuth not creating new user from Google authentication - Swift - swift

I am using the Google authentication to authenticate users on Firebase. The code runs without errors, however, I am not seeing any of the authenticated users under the "authentication" tab of the Firebase console. There is user activity according to the analytics, but there is no record of any of the users that sign in using the Google sign-in.
func sign(_signIn: GIDSignIn!, didSignInfor user: GIDGoogleUser!, withError error: Error!){
if let err = error {
print ("failed to log into Google", err)
return
}
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
accessToken: authentication.accessToken)
Auth.auth().signInAndRetrieveData(with: credential, completion: { (authResult, error) in
if let error = error {
print ("failed to create with google account")
return
}
// User is signed in
guard let uid = user?.userID else {
return
}
I followed the documentation on Firebase and I have enabled "Google sign-in". Thanks in advance!

I have found the answer to the issue:
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!){
if let err = error {
print ("failed to log into Google", err)
return
}
print("successfully logged into Google",user)
guard let idToken = user.authentication.idToken else {return}
guard let accessToken = user.authentication.accessToken else {return}
let credentials = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
Auth.auth().signInAndRetrieveData(with: credentials, completion: { (user, error) in
if let err = error {
print ("failed to create with google account", err)
return
}
print("successfuly logged into Firebase with Google", user?.user.uid)
})
}
The issue was with the first line of code, where "didSignInFor" was not properly capitalized. Likewise, there was a duplicate function that was calling the same sign-in function, which may have been another issue on why users were not showing up on the "authentication" tab of the Firebase console.

Related

What method to use instead of Auth.auth().signInAndRetrieveData?

enter image description here
im trying to auth through google and it seems like Auth.auth().signInAndRetrieveData is no more working.
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!){
if let err = error {
print ("failed to log into Google", err)
return
}
print("successfully logged into Google",user)
guard let idToken = user.authentication.idToken else {return}
guard let accessToken = user.authentication.accessToken else {return}
let credentials = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
Auth.auth().signInAndRetrieveData(with: credentials, completion: { (user, error) in
if let err = error {
print ("failed to create with google account", err)
return
}
print("successfuly logged into Firebase with Google", user?.user.uid)
})
}
Auth.auth().signIn(with: credential) { (result, error) in
if error == nil{
//use result info and do what you want here
}else{
//or other wise print the error description and looking it
print("This is the Error: \(error?.localizedDescription)")
}
}

Facebook Auth "An account already exists with the same email address but different sign-in credentials."

I have multiple login options for the user to choose from: email, google, and facebook. If Firebase already has the email stored as a user (ie. the user previously signed up with test#gmail.com), an alert that tells the user that an account with that email already exists. This works perfectly for Google sign in, as shown in this screenshot. However, nothing visually happens when the user clicks the Facebook button (doesn't even switch screens), and I get this error in the debugger:
Error Domain=FIRAuthErrorDomain Code=17012 "An account already exists with
the same email address but different sign-in credentials. Sign in using a
provider associated with this email address." UserInfo={FIRAuthErrorUserInfoNameKey=ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL,
FIRAuthErrorUserInfoEmailKey=318junkjabr#gmail.com,
FIRAuthErrorUserInfoUpdatedCredentialKey=<FIROAuthCredential:
0x6000005f3200>, NSLocalizedDescription=An account already exists with the
same email address but different sign-in credentials. Sign in using a
provider associated with this email address.}
This is my code for the Log In View Controller:
override func viewDidLoad() {
super.viewDidLoad()
setUpFBButton()
setUpGoogleButton()
setUpEmailButton()
GIDSignIn.sharedInstance()?.presentingViewController = self
}
// MARK: - SIGN UP WITH GOOGLE
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let err = error {
print("Failed to log into Google: ", err)
return
}
print("Successfully logged into Google")
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken)
// sign user in with Firebase
Auth.auth().signIn(with: credential, completion: { (user, error) in
let firstName = user?.user.displayName
let email = user?.user.email
let lastName = ""
let uid = user?.user.uid
if let err = error {
print("Failed to create a Firebase User with Google account: ", err)
return
} else {
// Successfully logged in
print("Successfully logged into Firebase with Google email: ", email ?? "", "Now add user to Firestore if user is new.")
// check if user already exists
self.addUserToFirestore(firstName ?? "", lastName, email ?? "", uid ?? "", "Google")
}
})
}
fileprivate func setUpGoogleButton() {
Utilities.styleLightFilledButton(signInGoogleButton)
signInGoogleButton!.addTarget(self, action:
#selector(handleCustomGoogleSignIn), for: .touchUpInside)
GIDSignIn.sharedInstance()?.delegate = self
}
#objc func handleCustomGoogleSignIn() {
GIDSignIn.sharedInstance().signIn()
}
// MARK: - SIGN UP WITH FACEBOOK
// design the facebook button and assign #selector to facebook button actions
fileprivate func setUpFBButton() {
Utilities.styleHollowButton(signInFacebookButton)
signInFacebookButton.addTarget(self, action: #selector(handleCustomFBButton), for: .touchUpInside)
}
// handle the facebook button actions
#objc func handleCustomFBButton() {
LoginManager().logIn(permissions: ["email", "public_profile"], from: self) { (result, err) in
if err != nil {
print("Custom FB login failed:", err!)
return
}
self.getUserInfo()
}
}
// grab id, name, and email of user
func getUserInfo() {
print("Successfully logged in with facebook...")
GraphRequest(graphPath: "/me", parameters: ["fields": "id, name, email"]).start {
(connection, result, err) in
guard let Info = result as? [String: Any] else { return }
let name = Info["name"] as? String
let email = Info["email"] as? String
let uid = Info["id"] as? String
if err != nil {
print("Failed to start graph request:", err!)
return
}
print(result!)
self.signIntoFirebase(name ?? "", email ?? "", uid ?? "")
}
}
// connect the user to firebase
func signIntoFirebase(_ name:String, _ email:String, _ uid:String) {
let credential = FacebookAuthProvider.credential(withAccessToken: AccessToken.current!.tokenString)
Auth.auth().signIn(with: credential) { (user, error) in
if let err = error {
print(err)
return
} else {
print("Facebook user successfully authenticated with Firebase. Now run through Firestore.")
// check if user already exists. if user exists, go to chats screen. if it does not exist, create a new user and redirect to chat screen.
self.addUserToFirestore(name, "", email, uid, "Facebook")
}
}
}
func loginButtonDidLogOut(_ loginButton: FBLoginButton) {
print("Logged out of facebook")
}
// MARK: - Other functions
func addUserToFirestore(_ firstName:String, _ lastName:String, _ email:String, _ uid:String, _ signInMethod:String) {
let db = Firestore.firestore()
let docRef = db.collection("users").document(uid)
// check if user exists in firestore
docRef.getDocument { (document, error) in
if let document = document {
if document.exists {
let message = "Good news! You already have a Coal account that uses " + email + ".\nPlease sign in to your existing account. Then you will be able to link your " + signInMethod + " profile from your Account Settings page."
// user exists. send to chats screen.
print("User already exists. Document data: \(String(describing: document.data()))")
self.showError("You're already a member!", message)
} else {
// user does not exist. create a new user
print("Document does not exist. Create new user.")
docRef.setData(["firstname":firstName, "lastname":lastName, "email":email]) { err in
if err != nil {
// Show error message
print("Error saving user data to Firestore")
} else {
print("New user created in Firestore")
self.transitionToConvo()
}
}
}
}
}
}
func showError(_ title:String, _ message:String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
func transitionToConvo() {
let tabBarC = self.storyboard?.instantiateViewController(withIdentifier: "mainTabBarController") as! TabBarController
tabBarC.modalPresentationStyle = .fullScreen
self.present(tabBarC, animated: true, completion: nil)
print("Switched to TabBarController")
}
func setUpEmailButton() {
Utilities.styleDarkFilledButton(signInEmailButton)
}
} // end
I think the reason why it's not getting an alert is because the Facebook uid doesn't match the email uid saved in Firestore (while Google uid does match). The way I'm getting the alert to show up is if the uid matches that in Firestore, so consequently, the alert doesn't show. Does anyone know how I can get the alert to show an how to not get this error?
I know my code is a bit messy, so please let me know if you need further explanation. Any help is appreciated!!
After hours of trying to figure out my problem, I decided to post a question... but almost immediately after, found the answer (i know right :/).
Since one account per email is already enabled in the project settings, Auth.auth().signIn automatically scans if a user exists. If a user exists, it'll return an error after if error != nil. Because it returned an error before my addUserToFirestore function was called (to check if the user exists and if not, add user to Firestore), the alert was never shown.
Now that we know what if error != nil means, we can just insert the alert there:
Auth.auth().signIn(with: credential) { (user, error) in
if error != nil {
let message = "Good news! You already have a Coal account that uses " + email + ".\nPlease sign in to your existing account. Then you will be able to link your Facebook profile from your Account Settings page."
// user exists. send to chats screen.
print("User already exists. Let user know.")
self.showError("You're already a member!", message)
return
}
I'm not sure why it worked for Google Auth, but it ended up that this is what worked for Facebook Auth.

(Firebase) After login with facebook, it won't return to my app

When I log in with Facebook in on a Real Device It will be stuck on the Facebook login page and don' return back to my app.
I have put facebook code in URL Schemes and put all code that need to put in info.plist.
This is all the code that i use to login Facebook by using firebase.
In Viewdidload
facebookButton.addTarget(self, action: #selector(handleCustomFBLogin), for: .touchUpInside)
Code that i use in Viewcontroller.
#objc func handleCustomFBLogin(sender:UIButton!){
LoginManager().logIn(permissions: ["email", "public_profile"], from: self) { (result, error) in
guard let result = result else {
print("No result found")
return
}
if result.isCancelled {
print("Facebook Login Cancelled")
} else if let error = error {
print("Process error \(error.localizedDescription)")
} else {
print("Logged in")
self.showEmailAddress()
self.actionfb()
}
}
}
func loginButton(_ loginButton: FBLoginButton, didCompleteWith result: LoginManagerLoginResult?, error: Error?){
if(error != nil){
print(error!)
return
}else{
print("Successfully Logged in using facebook")
showEmailAddress()
}
}
func actionfb(){
let accessToken = AccessToken.current
guard (accessToken?.tokenString) != nil else {return}
let credential = FacebookAuthProvider.credential(withAccessToken: accessToken!.tokenString)
// Perform login by calling Firebase APIs
Auth.auth().signInAndRetrieveData(with: credential) { (authResult, error) in
if let error = error {
self.showAlert(title: "error", message: "\(error.localizedDescription)")
return
}
self.performSegue(withIdentifier: "GoGo", sender: nil)
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
}
func showEmailAddress(){
GraphRequest(graphPath: "/me", parameters: ["fields" : "id, name, first_name, last_name, email, birthday, picture"]).start { (connection, result, err) in
if(err != nil){
print("Failed to start GraphRequest", err ?? "")
return
}
print(result ?? "")
}
}
func loginButtonDidLogOut(_ loginButton: FBLoginButton){
print("Logged out of Facebook")
}
In Appdelegate
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
This will happen only when i had test on real device!!, but in simulation this can work normally
I'm not exactly sure if this is the solution, but this fixed it for me.
I copied the OAuth redirect URI from my firebase, under Authentication -> Facebook
And then on my Facebook developer page, under Products -> Facebook Login -> Settings, I pasted it into Valid OAuth Redirect URIs
I then logged in by entering in my username and password into of clicking "Login with Facebook" and the error stopped happening.
I have no idea if the error will return, maybe this will be helpful to someone though.

A (swift) project is crashing when cancel facebook authentication

My project use Firebase and Facebook Authentication. It works fine, but when I choose to cancel the Facebook Authentication (the first time when i fetch the uid) the project crash.
Here is the method i use:
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
let credential = FacebookAuthProvider.credential(withAccessToken: FBSDKAccessToken.current().tokenString)
Auth.auth().signInAndRetrieveData(with: credential) { (user, error) in
// [START_EXCLUDE]
if let error = error {
print(error.localizedDescription)
return
}
self.uid = Auth.auth().currentUser?.uid
self.firstFetch()
// [END_EXCLUDE]
}
print("logged in")
}
Can Anyone help me, please?
Ok, the whole implementation of this function was wrong, because it was fetching the user no matter if it was authenticated or not. Here is the new method I wrote:
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result:
FBSDKLoginManagerLoginResult!, error: Error!) {
if error != nil {
print("look a at your.. errm.. code, please", error.localizedDescription)
} else if result.isCancelled {
print("houston, we have a situation: the player cancelled the auth request")
} else {
let credential = FacebookAuthProvider.credential(withAccessToken: FBSDKAccessToken.current().tokenString)
Auth.auth().signInAndRetrieveData(with: credential) { (user, error) in
self.uid = Auth.auth().currentUser?.uid
print("you're in, remember: with great power comes great responsibility!")
self.firstFetch()
}
}
}

Firebase Facebook login: An invalid API Key was supplied in the request

Trying to get Facebook login to work with the new Firebase, but I keep getting this error: "An invalid API Key was supplied in the request."
facebookLogin.logInWithReadPermissions(["public_profile", "email", "user_friends"], fromViewController: self) { (login, error) in
if error != nil {
print("Facebook login failed. Error \(error)")
} else if login.isCancelled {
print("Facebook login was cancelled.")
} else {
let accessToken = FBSDKAccessToken.currentAccessToken().tokenString
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(accessToken)
if let user = FIRAuth.auth()?.currentUser {
user.linkWithCredential(credential) { (sup, error) in
if let error = error {
print(error.localizedDescription)
return
}
}
} else {
FIRAuth.auth()?.signInWithCredential(credential) { (user, error) in
if let error = error {
// ERROR COMING FROM HERE
print(error.localizedDescription)
return
}
}
}
}
}
Follow the instructions from Google: https://support.google.com/cloud/answer/6158862?hl=en to get or create the API KEY of your iOS App.
Then you need to grab this API KEY and put it in the GoogleService-Info.plist as the:
Key: API_KEY
Value: the api key that you got.