Firebase error handling while creating user Swift - swift

I am currently developing an iOS application and I wanted to implement the Firebase database.
I'm facing an issue while handling errors during the users creation process. I always get the default error from the switch, here is my code :
FIRAuth.auth()?.createUser(withEmail: emailField.text!, password: passwordField.text!, completion: { (user, error) in
if (error != nil) {
if let errCode = FIRAuthErrorCode(rawValue: error!._code) {
var alertController = UIAlertController(title: "", message: "", preferredStyle: UIAlertControllerStyle.alert)
let okButton = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) {
(result: UIAlertAction) -> Void in
print("Error transmitted")
}
switch errCode {
case .errorCodeInvalidEmail:
print("Invalid email")
alertController = UIAlertController(title: "Error", message: "Email syntax is not correct", preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(okButton)
self.present(alertController, animated: true, completion: nil)
case .errorCodeEmailAlreadyInUse:
print("Email already in use")
alertController = UIAlertController(title: "Error", message: "This email is already in use", preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(okButton)
self.present(alertController, animated: true, completion: nil)
case .errorCodeWeakPassword:
print("Password weak")
alertController = UIAlertController(title: "Error", message: "Password is too weak. Please choose a password which contains at least 6 characters.", preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(okButton)
self.present(alertController, animated: true, completion: nil)
default:
// ALWAYS GET HERE.
print(error)
alertController = UIAlertController(title: "Error", message: "An unknown error occured.", preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(okButton)
self.present(alertController, animated: true, completion: nil)
}
}
} else {
print("User created")
let newUser = ["email": self.emailField.text!]
let firebaseNewUser = self.ref.childByAutoId()
firebaseNewUser.setValue(newUser)
}
Moreover, the print(error) displays :
Optional(Error Domain=FIRAuthErrorDomain Code=17999 "An internal error has occurred,
print and inspect the error details for more information."
UserInfo={NSUnderlyingError=0x170257be0 {
Error Domain=FIRAuthInternalErrorDomain Code=3 "(null)"
UserInfo={FIRAuthErrorUserInfoDeserializedResponseKey={
code = 400;
errors = (
{
domain = usageLimits;
message = "Bad Request";
reason = keyExpired;
}
);
message = "Bad Request";
}}},
error_name=ERROR_INTERNAL_ERROR,
NSLocalizedDescription=An internal error has occurred, print and inspect the
error details for more information.})
Can someone help me please ?

Try enabling identity toolkit API in google console.

Actually, (in answer to the previous message), the identity toolkit API was already activated.
The problem was coming from the fact that an API key was generated but was restrained to websites requests.
Solution : So I just generated another API key, restrained it to iOS applications, downloaded the .plist once again, put it into the project and add the API_KEY in it (API_KEY as an information property and the value as the new generated api key value)

For Created New User Please follow this simple code . Please put this code in Create Button #IBAction function.
FIRAuth.auth()?.createUserWithEmail(Username.text!, password: Password.text!
, completion: {
user , error in
if error != nil {
print("Something Went to Wrong :(")
}
else {
print("Account Created Sucessfully ")
}
})

Related

How can I get Firebase Auth to display an error?

I want to set up email/password authentication with firebase, and have this written which is similar to the documentation. I have only one registered email that I'm testing with, and when I attempt to sign in with that everything works well. But when I enter another email/password, the completion block does not execute.
Auth.auth().signIn(withEmail: email, password: password) { [weak self] (user, error) in
guard let strongSelf = self else {
return
}
if let error = error {
let errorAlert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
errorAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
strongSelf.present(errorAlert, animated: true, completion: nil)
return
}
}
Nevermind I fixed it. I had a performSegue line right outside of the completion, when it should have been inside, after the guard and if let statement.

How to show enter password and try again alert view

So I want to make a touchid authentication but if the touchid does not match there will be an alert to enter the password and try again
I am using XCode 9.0.0
#IBAction func ac(_ sender: Any) {
let context:LAContext=LAContext()
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil){
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "use your touch id", reply: {(wasCorrect,error) in
if wasCorrect {
print("correct")
}else{
print("incorrect")
}
})
}else{
}
}
The best way (from the users point of view) would be to enable / show a "Re-Authenticate" button if the authentication fails. Then, the user has to actively tap that button to re-run the autentication loop.
If you would automatically start re-authentication instead, the user might get annoyed by autentication dialogs popping up all the time, wich also might look a little weired because sometimes the animations overlap and the screen seems to flicker.
this will work, updated for swift 3 and 4
func authenticationWithTouchID() {
let localAuthenticationContext = LAContext()
localAuthenticationContext.localizedFallbackTitle = "Use Passcode"
var authError: NSError?
let reasonString = "To access the secure data"
if localAuthenticationContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) {
localAuthenticationContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString) { success, evaluateError in
if success {
//TODO: User authenticated successfully, take appropriate action
} else {
//TODO: User did not authenticate successfully, look at error and take appropriate action
guard let error = evaluateError else {
return
}
let message = self.evaluateAuthenticationPolicyMessageForLA(errorCode: error._code)
let alert = UIAlertController(title: "Alert", message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
} else {
guard let error = authError else {
return
}
let message = self.evaluateAuthenticationPolicyMessageForLA(errorCode: error._code)
let alert = UIAlertController(title: "Alert", message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
and methods to get the error messages
func evaluatePolicyFailErrorMessageForLA(errorCode: Int) -> String {
var message = ""
if #available(iOS 11.0, macOS 10.13, *) {
switch errorCode {
case LAError.biometryNotAvailable.rawValue:
message = "Authentication could not start because the device does not support biometric authentication."
case LAError.biometryLockout.rawValue:
message = "Authentication could not continue because the user has been locked out of biometric authentication, due to failing authentication too many times."
case LAError.biometryNotEnrolled.rawValue:
message = "Authentication could not start because the user has not enrolled in biometric authentication."
default:
message = "Did not find error code on LAError object"
}
} else {
switch errorCode {
case LAError.touchIDLockout.rawValue:
message = "Too many failed attempts."
case LAError.touchIDNotAvailable.rawValue:
message = "TouchID is not available on the device"
case LAError.touchIDNotEnrolled.rawValue:
message = "TouchID is not enrolled on the device"
default:
message = "Did not find error code on LAError object"
}
}
return message;
}
func evaluateAuthenticationPolicyMessageForLA(errorCode: Int) -> String {
var message = ""
switch errorCode {
case LAError.authenticationFailed.rawValue:
message = "The user failed to provide valid credentials"
case LAError.appCancel.rawValue:
message = "Authentication was cancelled by application"
case LAError.invalidContext.rawValue:
message = "The context is invalid"
case LAError.notInteractive.rawValue:
message = "Not interactive"
case LAError.passcodeNotSet.rawValue:
message = "Passcode is not set on the device"
case LAError.systemCancel.rawValue:
message = "Authentication was cancelled by the system"
case LAError.userCancel.rawValue:
message = "The user did cancel"
case LAError.userFallback.rawValue:
message = "The user chose to use the fallback"
default:
message = evaluatePolicyFailErrorMessageForLA(errorCode: errorCode)
}
return message
}
Hope this will help:
func authenticateUser() {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Identify yourself!"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) {
[unowned self] success, authenticationError in
DispatchQueue.main.async {
if success {
self.runSecretCode()
} else {
let ac = UIAlertController(title: "Authentication failed", message: "Sorry!", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
self.present(ac, animated: true)
}
}
}
} else {
let ac = UIAlertController(title: "Touch ID not available", message: "Your device is not configured for Touch ID.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
For more understanding: https://www.hackingwithswift.com/example-code/system/how-to-use-touch-id-to-authenticate-users-by-fingerprint
#IBAction func ac(_ sender: Any) {
let context:LAContext=LAContext()
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil){
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "use your touch id", reply: {(wasCorrect,error) in
if wasCorrect {
}else{
let myalert = UIAlertController(title: " Password Title", message: "Message ", preferredStyle: UIAlertControllerStyle.alert)
myalert.addAction(UIAlertAction(title: "Retry", style: .default) { (action:UIAlertAction!) in
print("retry")
})
self.present(myalert, animated: true)
}
})
}else{
// If You Wanna Show Alert
let myalert = UIAlertController(title: "Title", message: "Message ", preferredStyle: UIAlertControllerStyle.alert)
myalert.addAction(UIAlertAction(title: "Retry", style: .default) { (action:UIAlertAction!) in
print("retry")
})
self.present(myalert, animated: true)
}
}

iOS Firebase: Retrieve and match database code to pass through authentication

I'm trying to create an authentication security code for admin to login/ register. What I wish to do is login to perform segue if the user pass through the code which exists in firebase database. So now it doesn't works as Error alert box keep popping out event I have enter the correct security code.
let alertController = UIAlertController(title: "Security Code?", message: "Please enter your dedicated security code", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Next", style: .default) { (_) in
let code = alertController.textFields?[0].text
let scref=Database.database().reference();
scref.queryOrdered(byChild: "securitycode").queryEqual(toValue: code).observe(.value, with: { (snapshot) in
if (snapshot.exists())
{
Auth.auth().signIn(withEmail: self.emailText.text!, password: self.passwordText.text!, completion: { (user, error) in
if user != nil
{
//if sign in sucessful
self.performSegue(withIdentifier: "segueadmin", sender: self)
} else
{
if let myError = error?.localizedDescription{
print(myError)
let alertController = UIAlertController(title: "Error!", message: myError, preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default) {
UIAlertAction in
// Insert code to run on button click below
self.printYes()
})
self.present(alertController, animated: true, completion: nil)
}else{
print("ERROR")
}
}
})}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alertController.addTextField { (textField) in
textField.placeholder = "Enter Code:"
}
//adding the action to dialogbox
alertController.addAction(confirmAction)
alertController.addAction(cancelAction)
//finally presenting the dialog box
self.present(alertController, animated: true, completion: nil)
}
}
I think it might be an issue when you query your database.
Try this code :
scref.child("securitycode").child(code).observe(.value, with: { (snapshot) in
if (snapshot.exists()) {
...//Do your thing
}
With this your aim the reference /securitycode/{code} and if it exists it seems that there is a correct value stored in your database so you can proceed. If not the user can't proceed.
Oops! Very careless of me! It because of I didn't structure the data well and forgot to put " " for the data in Firebase.
So the firebase database should be:
And the code shall be:
ref=Database.database().reference().child("securitycode")
ref.queryOrdered(byChild: "code")
.queryEqual(toValue: self.textf.text)
.observe(DataEventType.value, with: { (snapshot) in

AWS Cognito: Trying to Alert User of Error

I am having difficulty in capturing a Cognito Sign Up Error. I am trying to alert the user when Cognito returns a "UsernameExistsException","message":"User already exists" Error.
Below is my code:
self.pool!.signUp(usernameTextField.text!, password: passwordTextField.text!, userAttributes: attributes, validationData: nil).continue(successBlock: { (task:AWSTask!) in
// needs to be async so we can ALWAYS return nil for AWSTask
DispatchQueue.main.async {
if task.error != nil { // some sort of error
let myerror = task.error
print("\(myerror)")
let alert = UIAlertController(title: "Sign Up Error", message: (task.error?.localizedDescription)! as String, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
else {
let response: AWSCognitoIdentityUserPoolSignUpResponse = task.result! as AWSCognitoIdentityUserPoolSignUpResponse
// NSLog("AWSCognitoIdentityUserPoolSignUpResponse: \(response)")
self.user = response.user
let alert = UIAlertController(title: "Sign Up Successful", message: "", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: { action in self.performSegue(withIdentifier: "confrimationSegue", sender: self) }))
self.present(alert, animated: true, completion: nil)
}
}
return nil
})
For some reason am unable to break into the task.error != nil conditional statement. When I force an error the error does not print and alert action does not present to the view. Am I attempting to alert the user in the wrong function? How else can I check for the Username Already Exists error presented by cognito. Thanks in advance.
You are using a successBlock, which means that the block that you set is only going to be called when the sign up was performed succesfully. That's why the error is always nil.
In order to have the error, you should set the callback simply by something like the following:
userPool
.signUp(user.email, password: user.password, userAttributes: attributes, validationData: nil)
.continue({ response in
if let error = response.error {
// Error ocurred
} else {
// No error ocurred
})
This continue method only recieves the callback and will be called when a error happens.

Duplicate email Alert Swift + Parse

I'm trying to have it so when a user creates an account... if their email hasn't been used before an Alert box appears saying "Account created" and if the email is already in created (on Parse) then an alert should appear notifying the user.
I can't seem to get my code to do both..only display one message. What am I doing wrong here?
Thanks!
func createNewUser() {
let newUser = PFUser()
newUser.email = emailSignUp.text
newUser.username = emailSignUp.text
newUser.password = passwordSignUp.text
newUser.signUpInBackgroundWithBlock { ( success: Bool, error: NSError?) -> Void in
if newUser.username != nil {
let alert: UIAlertController = UIAlertController(title: "Account created", message: "Please confirm your email", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "OK", style: .Default) { action -> Void in
}
alert.addAction(okButton)
self.presentViewController(alert, animated: true, completion: nil)
}
else {
let alert: UIAlertController = UIAlertController(title: "Email already registered", message: "Please enter a different email", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
alert.addAction(okButton)
self.presentViewController(alert, animated: true, completion: nil)
}
}
}
If memory serves the error that's returned if a user already exists is a different string than a generic error. You can try to match the error string and then display an alert if it matches or a different one if it's just an error (like the error string itself).
newUser.signUpInBackgroundWithBlock { ( success: Bool, error: NSError?) -> Void in
if error != nil {
if let errorString = error.userInfo?[“error”] as? String {
if errorString == “username \(emailSignUp.text) already taken” {
// Create alert that address is taken
} else {
// Create other case alert, though it may make sense to just display the error string in an alert box
}
}
} else {
// Do your usual stuff
}