I'm stuck with email verification with firebase. I've looked around for guidance but no help. After the user verifies his email, my code still prints out the user has not been verified. I'm still trying to get used to the syntax of firebase. Here is my code:
if FIRAuth.auth()?.currentUser!.emailVerified == true{
FIRAuth.auth()?.signInWithEmail(email.text!, password: passsword.text!, completion: {
user, error in
if error != nil{
print("Email/password is wrong or user does not exist")
}else{
print("Successful login.")
}
})
}else{
print("Please verify your email.")
}
here is my code for the sign up section:
let eduEmail = email.text
let endInEdu = eduEmail?.hasSuffix("my.utsa.edu")
if endInEdu == true {
FIRAuth.auth()?.createUserWithEmail(email.text!, password: passsword.text!, completion: {
user, error in
if error != nil{
let alert = UIAlertController(title: "User exists.", message: "Please use another email or sign in.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
print("Email has been used, try a different one")
}else{
FIRAuth.auth()?.currentUser!.sendEmailVerificationWithCompletion({ (error) in
})
let alert = UIAlertController(title: "Account Created", message: "Please verify your email by confirming the sent link.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
print("This is a college email and user is created")
}
})
}else{
print("This is not a my.utsa.edu email")
}
You checked if the user email was verified even before signing them in.
This is what worked for me.
FIRAuth.auth()?.signInWithEmail(txtUsername.text!, password: txtPassword.text!) {
(user, error) in
if let user = FIRAuth.auth()?.currentUser {
if !user.emailVerified{
let alertVC = UIAlertController(title: "Error", message: "Sorry. Your email address has not yet been verified. Do you want us to send another verification email to \(self.txtUsername.text).", preferredStyle: .Alert)
let alertActionOkay = UIAlertAction(title: "Okay", style: .Default) {
(_) in
user.sendEmailVerificationWithCompletion(nil)
}
let alertActionCancel = UIAlertAction(title: "Cancel", style: .Default, handler: nil)
alertVC.addAction(alertActionOkay)
alertVC.addAction(alertActionCancel)
self.presentViewController(alertVC, animated: true, completion: nil)
} else {
print ("Email verified. Signing in...")
}
}
}
You are using the coalescing operator after FIRAuth.auth() which means the following method call will return nil when FIRAuth.auth() was nil. If this is the case, your comparison with true will fail, since nil is not true.
I suggest you to refactor your code like this for easier debugging:
guard let auth = FIRAuth.auth(), user = auth.currentUser else {
print("No auth / user")
}
guard user.emailVerified else {
print("Email not verified")
return
}
guard let email = email.text, password = passsword.text else {
print("No email or password")
return
}
auth.signInWithEmail(email, password: password) { user, error in
if let error = error {
print("Email/password is wrong or user does not exist, error: \(error)")
} else {
print("Successful login.")
}
}
You should find your error easier like this.
Related
I'm currently developing an app that has a login page with a login button and main menu button. I've created everything and is working pretty well for the time being. I'm using Firebase as my backend database.
I wanted to create a 'forgot password' button which i already did and seems like its working but the only problem is it doesn't give me an alert when it sends the email, it just sends it, but i get the alert when i enter an email which is not in the user authentication. Below is my code for the forget password button:
#IBAction func frgtpassTapped(_ sender: Any) {
Auth.auth().sendPasswordReset(withEmail: emailTextField.text!) { error in
if self.emailTextField.text?.isEmpty==true{
let resetFailedAlert = UIAlertController(title: "Reset Failed", message: "Error: \(String(describing: error?.localizedDescription))", preferredStyle: .alert)
resetFailedAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetFailedAlert, animated: true, completion: nil)
}
if error != nil && self.emailTextField.text?.isEmpty==false{
let resetEmailAlertSent = UIAlertController(title: "Reset Email Sent", message: "Reset email has been sent to your login email, please follow the instructions in the mail to reset your password", preferredStyle: .alert)
resetEmailAlertSent.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetEmailAlertSent, animated: true, completion: nil)
}
}
}
I accept if anyone downvotes this post but please if you do, comment below the reason. Any help would be much appreciated!
Please this code
Auth.auth().sendPasswordReset(withEmail: emailTextField.text!) { error in
DispatchQueue.main.async {
if self.emailTextField.text?.isEmpty==true || error != nil {
let resetFailedAlert = UIAlertController(title: "Reset Failed", message: "Error: \(String(describing: error?.localizedDescription))", preferredStyle: .alert)
resetFailedAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetFailedAlert, animated: true, completion: nil)
}
if error == nil && self.emailTextField.text?.isEmpty==false{
let resetEmailAlertSent = UIAlertController(title: "Reset Email Sent", message: "Reset email has been sent to your login email, please follow the instructions in the mail to reset your password", preferredStyle: .alert)
resetEmailAlertSent.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetEmailAlertSent, animated: true, completion: nil)
}
}
}
It is clear from your code, that you are passing the unWrapped value to the closure, so the textField must contains some value in it.
THIS LINE IN YOUR CODE: if self.emailTextField.text?.isEmpty==true {
will never be entered inside condition.
It should be updated to like:
#IBAction func frgtpassTapped(_ sender: Any) {
//BEFORE SENDING DATA FOR AUTHENTICATION, CHECK FOR THE isEmpty CONDITIONS HERE
Auth.auth().sendPasswordReset(withEmail: emailTextField.text!) { error in
DispatchQueue.main.async {
if error != nil {
// YOUR ERROR CODE
} else {
//YOUR SUCCESS MESSAGE
}
}
}
}
When the user logs in with correct credentials SVProgressHUD shows and dismisses correctly, and the user segues correctly to the main home screen. However when the password or email is incorrect the SVProgressHUD shows endlessly and no alert is popping up.
#IBAction func signInButton(_ sender: Any) {
self.view.endEditing(true)
let email = emailText.text!.lowercased()
let finalEmail = email.trimmingCharacters(in: .whitespacesAndNewlines)
let password = passwordText.text!
if finalEmail.isEmpty || password.isEmpty {
let alertController = UIAlertController(title: "Error!", message: "Please fill in all the fields.", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
present(alertController, animated: true, completion: nil)
}else {
SVProgressHUD.show()
Auth.auth().signIn(withEmail: email, password: password) { (user, error) in
if error == nil {
if let user = user {
print("\(user.displayName!) has been signed in")
SVProgressHUD.dismiss()
// self.enter()
self.performSegue(withIdentifier: "signInHome", sender: nil)
}else{
SVProgressHUD.dismiss()
print("error")
let alertController = UIAlertController(title: "Low Blow!", message: "incorrect credentials", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(alertController, animated: true, completion: nil)
print(error?.localizedDescription as Any)
}
}
}
}
}
in case error is null you forget to dismiss the SVProgressHUD
checkout this code
#IBAction func signInButton(_ sender: Any)
{
self.view.endEditing(true)
let email = emailText.text!.lowercased()
let finalEmail = email.trimmingCharacters(in: .whitespacesAndNewlines)
let password = passwordText.text!
if finalEmail.isEmpty || password.isEmpty
{
let alertController = UIAlertController(title: "Error!", message: "Please fill in all the fields.", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
present(alertController, animated: true, completion: nil)
}
else
{
SVProgressHUD.show()
Auth.auth().signIn(withEmail: email, password: password)
{
(user, error) in
if error == nil
{
if let user = user
{
print("\(user.displayName!) has been signed in")
SVProgressHUD.dismiss()
self.performSegue(withIdentifier: "signInHome", sender: nil)
}
else
{
SVProgressHUD.dismiss()
print("error")
let alertController = UIAlertController(title: "Low Blow!", message: "incorrect credentials", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(alertController, animated: true, completion: nil)
print(error?.localizedDescription as Any)
}
}
else
{
SVProgressHUD.dismiss()
}
}
}
}
Since updating to Swift 3.0 even with the correct password I receive the incorrect message. Has anyone had this problem with authorizing users on Firebase?
#IBAction func LoginToAccount(_ sender: AnyObject) {
if let email = emailLogin.text, let password = passwordLogin.text {
FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: {
(user, error) in
if error != nil{
print("Incorrect")
let alert = UIAlertController(title: "Error", message: "Incorrect Email or Password.", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}else{
if error == nil {
self.performSegue(withIdentifier: "AdminSegue", sender: self)
}
}
})
}
}
}
If you could create an email and have problem with sign in then it would be like my case. Just check your keychain accessibility from yourproject.xcodeproject -> Capabilities -> keychain Sharing - > On if it is off.
After some research this is apparently an issue with Simulator 10.0 not allowing Firebase to write values to the keychain. Something they are working on apparently but it doesn't affect app on actual device.
You have to make sure the user has been created initially, because you have to create a user first and then sign in using the created user.
#IBAction func LoginToAccount(_ sender: AnyObject) {
if let email = emailLogin.text, let password = passwordLogin.text {
FIRAuth.auth()!.createUser(withEmail: email, password: password) { user, error in
if error == nil {
FIRAuth.auth()!.signIn(withEmail: email, password: password, , completion: { (user, error) in
if error != nil{
print("Incorrect")
let alert = UIAlertController(title: "Error", message: "Incorrect Email or Password.", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
} else {
if error == nil {
self.performSegue(withIdentifier: "AdminSegue", sender: self)
}
}
})
}
}
}
I'm trying to add error handling in creating user button in iOS project using swift and firebase:
Here's the code for the button:
#IBAction func Register(sender: AnyObject) {
if NameTF.text == "" || EmailTF.text == "" || PasswordTF.text == "" || RePasswordTF == "" || PhoneTF.text == "" || CityTF.text == ""
{
let alert = UIAlertController(title: "عذرًا", message:"يجب عليك ملىء كل الحقول المطلوبة", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
} else {
if PasswordTF.text != RePasswordTF.text {
let alert = UIAlertController(title: "عذرًا", message:"كلمتي المرور غير متطابقتين", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
} else {
FIRAuth.auth()?.createUserWithEmail(EmailTF.text!, password: PasswordTF.text!, completion: { user, error in
print(error)
if error != nil {
let errorCode = FIRAuthErrorNameKey
switch errorCode {
case "FIRAuthErrorCodeEmailAlreadyInUse":
let alert = UIAlertController(title: "عذرًا", message:"الإيميل مستخدم", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
case "FIRAuthErrorCodeUserNotFound":
let alert = UIAlertController(title: "عذرًا", message:"المستخدم غير موجود", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
case "FIRAuthErrorCodeInvalidEmail":
let alert = UIAlertController(title: "عذرًا", message:"الإيميل غير صحيح", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
case "FIRAuthErrorCodeNetworkError":
let alert = UIAlertController(title: "عذرًا", message:"خطأ في الاتصال بالانترنت", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
default:
let alert = UIAlertController(title: "عذرًا", message:"خطأ غير معروف", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
}
} else {
FIRAuth.auth()?.signInWithEmail(self.EmailTF.text!, password: self.PasswordTF.text!, completion: { (user: FIRUser?, error: NSError?) in
if let error = error {
print(error.localizedDescription)
} else {
self.ref.child("UserProfile").child(user!.uid).setValue([
"email": self.EmailTF.text!,
"name" : self.NameTF.text!,
"phone": self.PhoneTF.text!,
"city" : self.CityTF.text!,
])
print("Sucess")
// self.performSegueWithIdentifier("SignUp", sender: nil)
}
})
} //else
})
} //Big else
} //Big Big else
}
}//end of
I'm not sure if the syntax of the errors in switch statement is correct or not!
Because when I tested it in the simulator it always gives me the defualt case which is unknown error!
+
I could not find the syntax in the documentation:
https://firebase.google.com/docs/auth/ios/errors
So, What's the correct syntax to add error handling using new firebase and swift!
I've actually just struggled with this for quite a bit of time and found what the issue was. I've tried the code posted in an answer above and the error.code line gave me an error. It did work with error._code though. In other words, credit for the original answer to Paul with a slight modificaiton. Here's my final code (I will edit it for all errors though):
if let errCode = AuthErrorCode(rawValue: error!._code) {
switch errCode {
case .errorCodeInvalidEmail:
print("invalid email")
case .errorCodeEmailAlreadyInUse:
print("in use")
default:
print("Create User Error: \(error)")
}
}
Updated for Swift 4 + Firebase 4 + UIAlertController
extension AuthErrorCode {
var errorMessage: String {
switch self {
case .emailAlreadyInUse:
return "The email is already in use with another account"
case .userNotFound:
return "Account not found for the specified user. Please check and try again"
case .userDisabled:
return "Your account has been disabled. Please contact support."
case .invalidEmail, .invalidSender, .invalidRecipientEmail:
return "Please enter a valid email"
case .networkError:
return "Network error. Please try again."
case .weakPassword:
return "Your password is too weak. The password must be 6 characters long or more."
case .wrongPassword:
return "Your password is incorrect. Please try again or use 'Forgot password' to reset your password"
default:
return "Unknown error occurred"
}
}
}
extension UIViewController{
func handleError(_ error: Error) {
if let errorCode = AuthErrorCode(rawValue: error._code) {
print(errorCode.errorMessage)
let alert = UIAlertController(title: "Error", message: errorCode.errorMessage, preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(okAction)
self.present(alert, animated: true, completion: nil)
}
}
}
Usage example:
Auth.auth().signIn(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
print(error!._code)
self.handleError(error!) // use the handleError method
return
}
//successfully logged in the user
})
Even though this has been answered correctly, wanted to share a nice implementation for this we added to our project.
This can be done for other error types as well, but we just needed it for the FIRAuthErrorCodes.
If you extend FIRAuthErrorCode to have a variable errorMessage of type string, you can have your own error messages for the users:
extension FIRAuthErrorCode {
var errorMessage: String {
switch self {
case .errorCodeEmailAlreadyInUse:
return "The email is already in use with another account"
case .errorCodeUserDisabled:
return "Your account has been disabled. Please contact support."
case .errorCodeInvalidEmail, .errorCodeInvalidSender, .errorCodeInvalidRecipientEmail:
return "Please enter a valid email"
case .errorCodeNetworkError:
return "Network error. Please try again."
case .errorCodeWeakPassword:
return "Your password is too weak"
default:
return "Unknown error occurred"
}
}
}
You could customize only some as we have above and group the rest under "Unknown error".
With this extension you can handle an error as shown in Vladimir Romanov's answer:
func handleError(_ error: Error) {
if let errorCode = FIRAuthErrorCode(rawValue: error._code) {
// now you can use the .errorMessage var to get your custom error message
print(errorCode.errorMessage)
}
}
FIRAuthErrorCode is an int enum not a string enum. Do the following:
if let error = error {
switch FIRAuthErrorCode(rawValue: error.code) !{
case .ErrorCodeInvalidEmail:
More info in this answer.
I am using Swift 5 and Firebase 6.4.0 and for me, none of the above really worked. After trying around a bit I came up with this:
Auth.auth().createUser(withEmail: emailTextfield.text!, password: passwordTextfield.text!) { (user, error) in
if error!= nil{
let alert = UIAlertController(title: "Error", message: error!.localizedDescription, preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(okAction)
self.present(alert,animated: true)
}
I was registering users with Firebase, but newly created user can't be saved in Firebase though I've refreshed the Firebase Login & Auth tab.Could you help me fix it?
The code is here:
let saveAction = UIAlertAction(title: "Save", style: .Default) { (action:UIAlertAction) in
self.ref.createUser(self.textFieldLoginEmail.text, password: self.textFieldLoginPassword.text, withCompletionBlock: { (error:NSError!) in
if error == nil
{
self.ref.authUser(self.textFieldLoginEmail.text, password: self.textFieldLoginPassword.text, withCompletionBlock: { (error, auth) -> Void in
})
}
})
}
Try an figure out what is the error is when you try and log in, here an example for the use of the Firebase error log:
Data.ref.authUser(textFieldLoginEmail.text, password: textFieldLoginPassword.text, withCompletionBlock: { error, authData in
if error != nil {
var msg = ""
if let errorCode = FAuthenticationError(rawValue: error.code) {
switch (errorCode) {
case .UserDoesNotExist:
msg = "Invalid user name"
case .InvalidEmail:
msg = "Invalid email"
case .InvalidPassword:
msg = "Invalid password"
case .NetworkError:
msg = "we're sorry, network error has occurred, please login from the settings menu later"
default:
msg = "we're sorry, we encountered an error, please try again"
}
let alert = UIAlertController(title: "User Authentication error",
message: msg,
preferredStyle: .Alert)
let OKAction = UIAlertAction(title: "OK",
style: .Default) { (action: UIAlertAction!) -> Void in
if errorCode == .NetworkError {
self.performSegueWithIdentifier("ToMenuSegue", sender: self)
}
self.textFieldLoginPassword.text = ""
self.view.endEditing(true)
}
alert.addAction(OKAction)
self.presentViewController(alert, animated: true, completion: nil)
}
} else {
// Logged in
self.performSegueWithIdentifier("ToMenuSegue", sender: self)
}
})
The full Firebase errors list