Firebase iOS Authentication with an unconfirmed gmail account after Google Sign in - ios

Scenario:
A user creates a gmail.com email account and doesn't confirm it.
A user uses Google sign in button to log in. Firebase replaces his/her email accout to Google sign in account as the email hasn't been confirmed.
A user tries to log in with a gmail email account.
Question
What error should I catch to tell the user that an email has already been user with another method of authentication?
Code
func signIn(with email: String, and password: String) {
let credential = EmailAuthProvider.credential(withEmail: email, password: password)
Auth.auth().signIn(with: credential) { (user, error) in
if let error = error {
print(error.localizedDescription)
self.delegate.hideActivityIndicatorView()
if let errorCode = AuthErrorCode(rawValue: error._code) {
switch errorCode {
case .accountExistsWithDifferentCredential, .credentialAlreadyInUse:
self.delegate.presentAlert(title: "An account with this email already exists", message: nil)
case .userNotFound, .wrongPassword, .invalidEmail:
self.delegate.presentAlert(title: "Unable to Sign In", message: "Either email or password is incorrect.")
default:
self.delegate.presentAlert(title: "Something went wrong, please try again later.", message: nil)
return
}
}
}
print("Successful Email Sign In.")
self.delegate.hideActivityIndicatorView()
}
}

Related

SwiftUI Firebase: Sending a message to the mail

In the function I want to add sending a message to the confirmation email, if you confirm, then you get to Homescreen(), else SignUp().
What do I need to add to my code?
func register(){
if self.email != ""{
if self.pass == self.repass{
Auth.auth().createUser(withEmail: self.email, password: self.pass) { (res, err) in
if err != nil{
self.error = err!.localizedDescription
self.alert.toggle()
return
}
print("success")
UserDefaults.standard.set(true, forKey: "status")
NotificationCenter.default.post(name: NSNotification.Name("status"), object: nil)
}
}
else{
self.error = "Password mismatch"
self.alert.toggle()
}
}
else{
self.error = "Please fill all the contents properly"
self.alert.toggle()
}
}
SignUp() - View where registration takes place
Homescreen() - View where the message about successful registration appears
You can first try to sign the user in with email using following code:
Auth.auth().signIn(withEmail: email, link: self.link) { authResult, error in
// ...
}
If there is an error, present the error alert to the user.
If sign in was successful, you can use the following code to get the current user:
if let user = Auth.auth().currentUser {
}
And inside of the curly brackets just check if current user has already verified the E-Mail with user.isEmailVerified
If that is the case, then simply present your Homescreen
If current user has not verified his E-Mail yet, you can present an alert, where the user can choose if he wants to have the verification E-Mail sent out again. If that is the case, you can simply resend the E-Mail with
user.sendEmailVerification {error in
}
and the user will get his verification E-Mail or there can occur an error while sending the Email so you should handle that error aswell!
Good luck!
You can also check the Firebase docs for Email Verification

How to detect if an email address change was reverted?

I was working on the user profile page of my app and I am allowing the user to change their email address. If the user email address is changed successfully, the data in the firebase database of the particular user will be updated. Also, After successfully changing the email address, firebase will send an email to the user's previous email address (the user email address before it was changed to the new one) asking if it was the actual owner of the account who changed the email address and there will be a link to reset their email. If the user chooses to reset the email (for whatever reason), the user's new email will be changed to the previous email. But the problem is that the data in the database will not be updated, how can I detect this change (email reset) and update the database?
authenticateUserAlert.addAction(UIAlertAction(title: "Done", style: .default, handler: { [weak authenticateUserAlert] (_) in
// Print the user email
let emailTextField = authenticateUserAlert?.textFields![0]
print("Email: \(emailTextField!.text!)")
// Print the user password
let passwordTextField = authenticateUserAlert?.textFields![1]
print("Password: \(passwordTextField!.text!)")
// Re-authenticate the user
let user = Auth.auth().currentUser
let credential = EmailAuthProvider.credential(withEmail: emailTextField!.text!, password: passwordTextField!.text!)
user?.reauthenticate(with: credential, completion: { (result, error) in
if error != nil {
// Alert: What ever the error
print(error!.localizedDescription)
Alerts.errorAlert(on: vc, error: error!.localizedDescription, dismissAlert: false)
} else {
print(result!)
let editProfilePage = EditUserProfile()
editProfilePage.updateUserInfo()
}
})
}))
Here is what I tried according to an answer
Auth.auth().currentUser?.reload(completion: { (Error) in
//Completion handler
if let email = Auth.auth().currentUser?.email {
UserDataRetrieval.userEmail = email
self.emailLabel.text = email
print(Auth.auth().currentUser?.email)
}
})
It depends on the type of authentication you are using but honestly you should just use the email that is part of the authenticated account and then you don't need to worry about updating it in the database.
You can always just get the users email by using Auth.auth().currentUser.email
Update
Found a workaround to the issue of the credential data, try using
Auth.auth().currentUser?.reload(completion: { (Error) in
if (Error != nil) {
//Do something with error
} else {
//Do something with success or do nothing
}
})
Just call update credentials at the start of the app if you want to always have to most up to date credentials
You can always build your own custom handler for the email change revocation landing page. In that landing page you can update your database.
Check the official docs on how to do that.

Log Out Facebook User When Authenticated With Firebase Auth

I have the following code that authenticates a user with Facebook and then with Firebase:
func authenticateWithFacebook() {
FBSDKLoginManager().logIn(withReadPermissions: ["public_profile"], from: self) { (user, error) in // Signs up user with Facebook
if let error = error {
print(error.localizedDescription)
} else if (user!.isCancelled) { // User cancels sign up
print("User Cancelled")
} else {
self.authenticateFacebookUserWithFirebase(credential: FacebookAuthProvider.credential(withAccessToken: FBSDKAccessToken.current().tokenString))
}
}
}
func authenticateFacebookUserWithFirebase(credential: AuthCredential) {
Auth.auth().signInAndRetrieveData(with: credential) { (user, error) in
if let error = error {
print(error.localizedDescription)
} else {
print("Success")
}
}
}
This code works as expected. Once the user is authenticated with Firebase, what do I do with the Facebook user that has been "created" in the app? Do I need to keep track of the currentAccessToken and alert Firebase auth when the token expires? If not, do I just leave the code as is or should I log the Facebook user out of my app using the FBSDK? I just don't want a Facebook token floating around in my app.
The user is not logged in to Firebase with Facebook as such. Your app does not get the user's facebook email and password credentials in order to log them into your app's Firebase. Instead it gets the access token for that user and then that token is used to authenticate the user with Firebase. Therefore you cannot log out your user from Facebook but what you can do is invalidate the access token.

firebase Re-Authentication ios

I'm trying to make User Authentication but I got the error:
Credential used before its being initialized
My code below:
if error._code == 17014 {
// required recent authentication
let credential: AuthCredential
user.reauthenticateAndRetrieveData(with: credential, completion: nil)
}
}else {
self.ShowAlert(title: "succeed", message: "mail Updated")
}
})
}
}))
You need to initialize the credential. If this is an email/password user, you should ask the user to provide the password. If this is an OAuth user, get a new OAuth credential. You would then initialize the Firebase AuthCredential with those and reauthenticate.

Incorrect argument label in call (have 'email:password:', expected 'withEmail:password:')

I get this : Incorrect argument label in call (have 'email:password:', expected 'withEmail:password:')
While tryin to sign up user with email and password !!
I have looked at the firebase documents here But didn't have a clue of why not working
The error says withEmail is invalid but it comes default with Firebase call function as
EmailAuthProvider.credential(withEmail email: String, password:
String) -> AuthCredential
Found a similar issue here as well But couldn't get it right !!
all my pods are updated
I used the autocomplete functionality of Xcode and found that this is the function:
EmailAuthProvider.credential(withEmail: String, password: String)
If you are using Authenticate with Firebase using Password-Based Accounts Use this reference
Use this for method instead.
For Create a password-based account
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
// ...
}
And For Sign in a user with an email address and password
Auth.auth().signIn(withEmail: email, password: password) { (user, error) in
// ...
}
At last For sign out a user
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
You can find documentation on this link: https://firebase.google.com/docs/auth/ios/password-auth

Resources