Swift iOS Firebase -If the FirebaseAuth.FIRUser Object isn't nil how is it possible for the .email on it to return nil?

Lance Samaria

I use Firebase's Email/Password Sign-In Method to create an account for a user. Using that method the user must have an email address to get authenticated into Firebase.

FirebaseAuth has a FIRUser object named User

enter image description here

When a user first creates an account or logs into an existing account in the callback the User object gets initialized:

Create Account:

Auth.auth().createUser(withEmail: emailTextField.text!, password: passwordTextField.text!, completion: {
            (user, error) in

            // user's auth credentials are now created but user can still be nil

Logging into existing account:

Auth.auth().signIn(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!, completion: {
            (user, error) in

            // user's auth credentials are now accessed but user can still be nil

The User object has an .email Optional of type String on it that contain's the user's email address.

enter image description here

I use a singleton class to manage everything that happens through Firebase and in both situations above when the User objects gets initialized I pass that data through to my Firebase singleton's class properties. I know the User object can come back as nil so I run an if-let to make sure it isn't.

My question is if using the Email/Password Sign-In Method if the User object isn't nil in the callback is it possible that the .email can be nil even though it's necessary to have it to make an account or log in?

After I run the if-let statements I use guard statements to check and see if the .email isn't nil but it seems like it either can run before the the FirebaseSingleton properties gets initialized (which means it will be nil) or it might be unnecessary if the User object is guaranteed to return it with a value.

Btw in both situations wether the user is creating and account or logging in the emailTextFiled and passwordTextField will not be nil. I run whitespace, .isEmpty, and != nil checks on them.

My Code:

class FirebaseSingleton{

    static let sharedInstance = FirebaseSingleton()

    var dbRef: DatabaseReference? = Database.database().reference()
    var storageDbRef: StorageReference? = Storage.storage().reference(forURL: "gs://blablabla.appspot.com")
    var currentUser: User? = Auth.auth().currentUser
    var currentUserID: String? = Auth.auth().currentUser?.uid
    var currentUserEmail: String? = Auth.auth().currentUser?.email
    var currentUserPhotoUrl: URL? = Auth.auth().currentUser?.photoURL
    var currentUserDisplayName: String? = Auth.auth().currentUser?.displayName
}

Creating an Account:

Auth.auth().createUser(withEmail: emailTextField.text!, password: passwordTextField.text!, completion: {
                (user, error) in

                if error != nil { return }

                if let user = user{

                    let sharedInstance = FirebaseSingleton.sharedInstance
                    sharedInstance.currentUser = user
                    sharedInstance.currentUserID = user.uid
                    sharedInstance.currentUserEmail = user.email // at this point is it possible for this to be nil?
                    sharedInstance.currentUserPhotoUrl = user.photoURL
                    sharedInstance.currentUserDisplayName = user.displayName
                }else{
                   return
                }

                // is this guard statement necessary?
                guard let email = user.uid else { return }
})

Logging into an existing account:

Auth.auth().signIn(withEmail: emailTextField.text!, password: passwordTextField.text!, completion: {
                (user, error) in

                if error != nil { return }

                if let user = user{

                    let sharedInstance = FirebaseSingleton.sharedInstance
                    sharedInstance.currentUser = user
                    sharedInstance.currentUserID = user.uid
                    sharedInstance.currentUserEmail = user.email // at this point is it possible for this to be nil?
                    sharedInstance.currentUserPhotoUrl = user.photoURL
                    sharedInstance.currentUserDisplayName = user.displayName
                }else{
                   return
                }

                // is this guard statements necessary?    
                guard let email = user.uid else { return }
})
Lance Samaria

After having a convo with @Benjamin Jimenez and per @kbunarjo suggestions I did some thinking and I realized that Firebase also has a Phone Sign-In Method. If it's enabled and a user chooses that as their sign-in method then the .email address would be nil because there wouldn't be an email address used to create an account.

enter image description here

For my situation since I'm using the Email/Password Sign-In Method then the .email should not be nil because it is the only way to create an account. But just as User can come back as nil in the completion handler (even with the correct email and password) maybe it’s possible that the email address can also come back as nil since it’s an Optional.

That being said the safest method to use would be another if-let to check to see if the user.email isn't nil and if for some strange reason that it is then use the email address that was entered into the emailTextField as an alternative. The email address entered into the emailTextField and password combo has to be correct otherwise the user won't get authenticated into Firebase and error != nil.

Auth.auth().signIn(withEmail: emailTextField.text!, password: passwordTextField.text!, completion: {
                (user, error) in

                // if the email address and/or password are incorrect then error != nil and the code below this wont run
                if error != nil { return }

                if let user = user{

                    let sharedInstance = FirebaseSingleton.sharedInstance
                    sharedInstance.currentUser = user
                    sharedInstance.currentUserID = user.uid
                    sharedInstance.currentUserPhotoUrl = user.photoURL
                    sharedInstance.currentUserDisplayName = user.displayName

                    // instead of the guard statement I use another ‘if-let’ if for some reason .email is nil
                    if let currentUserEmail = user.email {
                              sharedInstance.currentUserEmail = currentUserEmail
                         }else{
                              sharedInstance.currentUserEmail = self.emailTextField.text! // the email address entered into here has to be valid otherwise it would've never made it to this point
                    }
                }else{
                   return
                }
})

Use the same exact code for the callback if Creating an Account

As @rMickeyD noted the Facebook Sign-In Method won’t use the email address either. I’ve never used it so I didn’t include it. Basically if none of the other Sign-In Methods don’t use your email address then user.email will be nil. Even if though I have Anonymous Sign-In as an option the method to use Anonymous Sign-In doesn’t require an email address nor a password so it’s understood that email will be nil.

You should check the docs to see if they require the email or not for all the other Sign-In Methods but the Phone number doesn’t need it.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related