How to detect if an email address change was reverted? - ios

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.

Related

Failure to login straight after verifying but successful on second tap

I am creating an app that allow user sign up/login through Firebase API. The flow is that the user signs up a new account, is taken to an email verification page (the user is sent a verification email at this point), then they may login after verifying their account. The problem is, on the first time they tap "Login", the alert is shown that they still need to be verified (even after verifying) but when they tap again it will successfully log them in. I want the user to be able to login successfully first time straight after verifying. Thank you in advance for the help.
private func login() {
let userEmail = textFrom(loginEmail)
let userPassword = textFrom(loginPassword)
let authUser = Auth.auth().currentUser
self.loginButton.loadingIndicator(show: true)
guard let isVerified = authUser?.isEmailVerified else { return }
Auth.auth().signIn(withEmail: userEmail, password: userPassword, completion: {(user, error) in
if let firebaseError = error {
self.loginButton.loadingIndicator(show: false)
self.showError(firebaseError)
}
if authUser != nil && !isVerified {
self.loginButton.loadingIndicator(show: false)
self.presentAlert(withTitle: "Verify Email", message: "Please verify your email first before logging in")
self.clearFields()
} else {
self.loginButton.loadingIndicator(show: false)
self.transitionToHome()
}
})
}
Also, I know this isn't Github but I am new to using Firebase, if you think my logic can be improved (this function is called in the IBAction of the login button) then please let me know. Thank you :)
Are you positive that the alert you quoted is the one being returned? No other similarly worded alerts coming from somewhere else?
If so, then the only way it can be shown is if isVerified is false and authUser is not nil (which is redundant, because if it was nil, the guard let ... optional chaining would have immediately returned from the function).
So it looks like authUser.isEmailVerified is returning false. You can verify this by adding a breakpoint at the line: if authUser != nil && !isVerified {
Without knowing more it's impossible to say what's going on.

Firebase Auth and Swift: Check if email already in database

I'm working on an iOS app which will use Firebase for user management (sign up, sign in, etc.)
I'm new to Firebase, but it's mostly going ok. I've connected it, I have created users and logged in, etc.
But, I'm trying to change my UI so that the "Sign up" button is initially hidden and will only appear when:
all fields are not empty
email address is valid (using regex)
email address in not already in the database
user name is not already in the database
password and confirmPassword fields are equal
I can't figure out #3 and #4.
I've been reading documentation, watching videos, chasing links all over StackO and beyond, but I can't figure it out.
Can anyone point me in the right direction?
If you are using email & password authentication, the solution is very simple.
Firebase Authentication will not allow duplicate emails so when the createUser function is executed, if the email already exists Firebase will return a emailAlreadyInUse error in the error parameter. You can then cast this to an NSError to see which one it is and handle appropriately.
So the function is like this
Auth.auth().createUser(withEmail: createEmail, password: password ) { user, error in
if let x = error {
let err = x as NSError
switch err.code {
case AuthErrorCode.wrongPassword.rawValue:
print("wrong password")
case AuthErrorCode.invalidEmail.rawValue:
print("invalid email")
case AuthErrorCode.accountExistsWithDifferentCredential.rawValue:
print("accountExistsWithDifferentCredential")
case AuthErrorCode.emailAlreadyInUse.rawValue: //<- Your Error
print("email is alreay in use")
default:
print("unknown error: \(err.localizedDescription)")
}
//return
} else {
//continue to app
}
I threw some random errors into that case statement but check the link for a complete list of all AuthErrorCodes.
You can also do this
Auth.auth().fetchSignInMethods(forEmail: user, completion: { (signInMethods, error) in
print(signInMethods)
})
I think you can check it by using this method
let ref1 = Database.database().reference().child("Users").queryOrdered(byChild: "UserName").queryEqual(toValue: "UserName enter by user")
ref1.observeSingleEvent(of: .value) { (sanpshot) in
print(sanpshot.exists()) // it will return true or false
}
and same for email.

How to set up Firebase iOS authentication email

Having looked through lots of previous questions and looking on the Firebase website documentation, it keeps leading me back to the snippet of code I need in my VC, BUT not how to actually set it up?.
Firstly in the email address verification setup on Firebase
I've by mistake put my personal email address as the 'reply to' email - do I put my personal (not business) email in there/how would I change it? Apologies for any over the top censoring (not sure what is private and not)
Secondly in my SignUpViewController what do I put as the URL String and what do I put as my IOSBundleID? Many thanks!
To change the email go to Authentication and press templates. There you have some options for your mail.
Press the pen beside noreply#yourfirebase.firebaseapp.com.
There you will have a replay to line and you can change all those settings
This is all you need to register a new user :
Auth.auth().createUser(withEmail: emailText.text!, password: passwordText.text!) {
(user, error) in
if error != nil {
print(error.localizedDescripton)
}else {
print("registration successful")
}
}
To send confirmation email to user make a call after user is created and use this method :
func sendConfirmationEmail() {
// Here you check if user exist
if self.authUser != nil && !self.authUser!.isEmailVerified {
self.authUser!.sendEmailVerification(completion: { (error) in
// Send the email
})
}
else {
// ERROR
}
}
You could now call the second method after user been created and the user will get an email

Firebase phone Authenication iOS

I am currently authenticating users using firebase phone Authentication and it works fine, however when I close the app and open it again I am redirected to the Authentication form and I receive an authentication Code each time. I don't want that kind of behavior. Is there is a way to check if the current user or the phone number is already authenticated without saving the user to a database
You can do it like checking for the currentUser in firebase, if the currentUser's phone number is same as the provided phone number in textField, then you can bypass the authentication and take user to home screen. Here is how it can be done.
if Auth.auth().currentUser != nil {
// USER IS SIGNED IN, BUT STILL WE HAVE TO CHECK, IF THE SAME USER IS SIGNING IN OR DIFFERENT.
if let user = Auth.auth().currentUser {
let phone = user.phone
if phone == YOUR TEXTFIELD VALUE OF PHONE {
// YOU HAVE THE LOGGED IN USER NOW, YOU CAN TAKE USER TO HOME SCREEN
} else {
// SIGNOUT THE CURRENT USER AND DO THE AUTHENTICATION FOR NEW USER
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
// No USER IS SIGNED IN, SO GET CREDENTIAL FROM YOUR SERVER AND SEND IT TO AUTH
Auth.auth().signIn(withCustomToken: customToken ?? "") { (user, error) in
// YOU HAVE THE LOGGED IN USER NOW, YOU CAN TAKE USER TO HOME SCREEN
}
}
}
} else {
// No USER IS SIGNED IN, SO GET CREDENTIAL FROM YOUR SERVER AND SEND IT TO AUTH
Auth.auth().signIn(withCustomToken: customToken ?? "") { (user, error) in
// YOU HAVE THE LOGGED IN USER NOW, YOU CAN TAKE USER TO HOME SCREEN
}
}
Check the procedure, if this is what you wants to achieve.

Firebase Facebook login check if user exist

I have an facebook login system which works with firebase but I want to check if user exist on my firebase (i don't want to add it, just want to make sure if he exist because I want to redirect user to another page to complete its profile, once its done I'll want to send it to firebase).
I just need to check if user exist on my db. Here is the code that I try but it returns nil error and it automatically add user to firebase.
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(FBSDKAccessToken.currentAccessToken().tokenString)
FIRAuth.auth()?.signInWithCredential(credential) { (user, error) in
// ...
}
You can use reauthenticateWithCredential method to check user is exist or not.
Check this Doc. , section -> Re-authenticate a user
let user = FIRAuth.auth()?.currentUser
var credential: FIRAuthCredential
// Prompt the user to re-provide their sign-in credentials
user?.reauthenticateWithCredential(credential) { error in
if let error = error {
// An error happened.
} else {
// User re-authenticated.
}
}
If user re-authenticated successfully that means user is existed...

Resources