0

I'm having an issue with Firebase and it's email verification flow. I'm able to create a new user, email with a link to verify email address is delivered with no issues. Now, just for testing purposes I'm not clicking on the link to verify the email, but, if I open the app, I'm able to access and do anything. I'm not sure what I'm missing or what I'm doing wrong. I've been stuck with this for the past couple days. Any help is greatly appreciated.

my code

@IBAction func loginBtnTapped(_ sender: Any) {

    SVProgressHUD.show()
    guard let email = emailTxt.text,
        let password = passwordTxt.text else { return }

    Auth.auth().signIn(withEmail: email, password: password) { 
(user, error) in
        if error != nil {
            let alert = UIAlertController(title: "Login Error", 
message:"Incorrect Email and/or Password", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: 
.default) { _ in })
            self.present(alert, animated: true){}
            if let error = error {
                print("error: \(error.localizedDescription)")
            }
           if Auth.auth().currentUser?.isEmailVerified == false {
                let alert = UIAlertController(title: "Unable to 
login", message:"Pending: email verification", preferredStyle: 
.alert)
                alert.addAction(UIAlertAction(title: "OK", style: 
.default) { _ in })
                self.present(alert, animated: true){}
                print("")
            SVProgressHUD.dismiss()
            }
        }
            self.dismiss(animated: true, completion: nil)
            SVProgressHUD.dismiss()
        }
    }

Expected results

Newly created user should not be able to login and open the app unless email is verified.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Eddie
  • 137
  • 1
  • 13
  • Firebase Authentication allows user to sign in who enter the right credentials, regardless of their email verification status. Are you saying you don't get the `Unable to login` alert? – Frank van Puffelen Oct 23 '19 at 03:58
  • Hi Frank, i thought that the purpose of the email verification is to avoid unauthorized users. I don't want for a random user to create an account and just access the info. I'm able to access without "verification of my email address", thus, the Unable to login alert does not come up. Thank you – Eddie Oct 23 '19 at 04:07
  • Firebase Authentication is about **authenticating** users. If you type (say) the correct email address and password, we trust that you are you. If you only want to allow data access to users who have verified their email address, that is possible (and know as **authorization**). You'll check this in the backend that you're trying to protect though, for example in security rules of your Firestore database, as shown here https://stackoverflow.com/a/50239804. – Frank van Puffelen Oct 23 '19 at 14:11

4 Answers4

2

Firebase Authentication is about authenticating users. If you type (say) the correct email address and password, we trust that you are you.

If you only want to allow data access to users who have verified their email address, that is possible (and know as authorization). You'll check this in the backend that you're trying to protect though, for example in security rules of your Firestore database, as shown here (Firebase) Firestore security rules - allow if email verified without custom tokens?

Also see

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
1

you need to check on the firebase databasae for the field that says "is email verified" and then if that BOOL value is TRUE, then let them in the app. the bool value will turn to TRUE automatically after they click the link in their email. so instead of doing it like your'e doing, query the user table for that user and check the boolean value for whether they are verified, if they are not, then don't let them in. good luck and have a fabulous day

Larry Pickles
  • 4,615
  • 2
  • 19
  • 36
0

You should keep the user account disabled until the email address is verified. That seems to be the only way to securely forbid login.

Typically, you may use sendSignInLinkToEmail() to send an email address validation message with specific URL. The user will be automatically redirected to this url after the email validation process.

In our case, we invite user to create a password and then activate their account before redirecting them to the login screen.

Olivier Lépine
  • 618
  • 5
  • 14
  • do you create the account and keep them disabled until the email is verified? or is there a way that when the user creates the account from the app is disabled until the verification? if yes, i there a post i can take a look at. – Eddie Oct 23 '19 at 15:34
  • Accounts are created disabled with basic information (email, preferred language) and an email invite is sent. After some time we can delete accounts which are disabled with an unverified email address. – Olivier Lépine Oct 24 '19 at 11:58
0

I was able to get this working as expected. The user needs to verify the email, if not, they cannot access the app. I did not have to modify the rules in Firebase. Hope this helps anyone.

loginVC

private var authUser : User? {
        return Auth.auth().currentUser
    }
    public func verifyEmail() {
        authUser?.reload(completion: { (err) in
            if err == nil {
                if self.authUser!.isEmailVerified == true {
                   self.dismiss(animated: true, completion: nil)
                } else {
                    let alert = UIAlertController(title: "Confirm your email 
address.", message: "A confirmation email has been sent to" + "  " + 
((self.emailTxt.text)!) + " . " + "Click on the confirmation link to activate 
your account. ", preferredStyle: .alert)
                    let actionTaken = UIAlertAction(title: "OK", style: 
.default, handler: nil)
                    alert.addAction(actionTaken)
                    self.present(alert, animated: true, completion: nil)
                }
            }
        })
    }


    @IBAction func loginBtnTapped(_ sender: Any) {
        SVProgressHUD.show()
        guard let email = emailTxt.text,
            let password = passwordTxt.text else { return }

        Auth.auth().signIn(withEmail: email, password: password) { (user, 
error) in
            self.verifyEmail()
            if error != nil {
                let alert = UIAlertController(title: "Login Error", 
message:"Error: \(error!.localizedDescription)", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .default) { _ 
in })
                self.present(alert, animated: true){}
                if let error = error {
                    print("error: \(error.localizedDescription)")
                }
            }
            SVProgressHUD.dismiss()
        }

    }
Eddie
  • 137
  • 1
  • 13