最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - Firebase Authentication SwiftUI: Email verification status becomes true after password change - Stack Overflow

programmeradmin4浏览0评论

I'm using Firebase Authentication in my iOS app and have implemented email verification during user registration. I also check for unverified emails upon sign-in and require users to verify their email before accessing the app, which is working as expected. However, I've noticed an unexpected behavior:

  1. User signs up with email and password but doesn't verify their email.
  2. User is not allowed to enter the app due to the email verification check.
  3. User resets password without verifying email.
  4. After changing the password, the user can access the app because isEmailVerified becomes true.

I expected isEmailVerified to remain false after a password change since email verification and password change are separate processes. The user should still be required to verify their email before accessing the app. Is this behavior expected in Firebase Authentication?

Code:

@MainActor
    func signInWithEmail() async {
        isLoading = true
        
        validateEmail()
        validatePassword()
        
        if emailCredentials.email.isEmpty {
            emailValidationState.email = .invalid("Email is required")
            isLoading = false
            return
        }
        if emailCredentials.password.isEmpty {
            emailValidationState.password = .invalid("Password is required")
            isLoading = false
            return
        }
        
        guard case .valid = emailValidationState.email,
              case .valid = emailValidationState.password else {
            isLoading = false
            return
        }
        
        do {
            let result = try await authService.signInWithEmail(
                email: emailCredentials.email,
                password: emailCredentials.password
            )
            print("BBBB \(result.user.isEmailVerified)")
            if !result.user.isEmailVerified {
                emailVerificationState.credentials = AuthenticationModel.CreateAccountCredentials(
                    email: emailCredentials.email,
                    password: emailCredentials.password
                )
                emailVerificationState.email = emailCredentials.email
                try await result.user.sendEmailVerification()
                emailAuthAlert.message = AppConstants.Alert.Message.format(
                    AppConstants.Alert.Message.emailVerificationSent,
                    with: emailCredentials.email
                )
                emailAuthAlert.showAlert = true
                
            } else {
                handleSuccessfulAuthentication(for: .email)
            }
            
        } catch {
            handleAuthError(error, for: .emailAuth)
        }
        
        isLoading = false
    }

@MainActor
func resetPassword() async {
    isLoading = true
    
    validateResetPasswordEmail()
    
    if resetPasswordCredentials.email.isEmpty {
        resetPasswordValidationState.email = .invalid("Email is required")
        isLoading = false
        return
    }
    
    guard case .valid = resetPasswordValidationState.email else {
        isLoading = false
        return
    }
    
    do {
        try await authService.resetPassword(email: resetPasswordCredentials.email)
        fotPasswordAlert.message = AppConstants.Alert.Message.format(
            AppConstants.Alert.Message.passwordResetSent,
            with: resetPasswordCredentials.email
        )
        
        fotPasswordAlert.showAlert = true
    } catch {
        handleAuthError(error, for: .fotPassword)
    }
    
    isLoading = false
}

I'm using Firebase Authentication in my iOS app and have implemented email verification during user registration. I also check for unverified emails upon sign-in and require users to verify their email before accessing the app, which is working as expected. However, I've noticed an unexpected behavior:

  1. User signs up with email and password but doesn't verify their email.
  2. User is not allowed to enter the app due to the email verification check.
  3. User resets password without verifying email.
  4. After changing the password, the user can access the app because isEmailVerified becomes true.

I expected isEmailVerified to remain false after a password change since email verification and password change are separate processes. The user should still be required to verify their email before accessing the app. Is this behavior expected in Firebase Authentication?

Code:

@MainActor
    func signInWithEmail() async {
        isLoading = true
        
        validateEmail()
        validatePassword()
        
        if emailCredentials.email.isEmpty {
            emailValidationState.email = .invalid("Email is required")
            isLoading = false
            return
        }
        if emailCredentials.password.isEmpty {
            emailValidationState.password = .invalid("Password is required")
            isLoading = false
            return
        }
        
        guard case .valid = emailValidationState.email,
              case .valid = emailValidationState.password else {
            isLoading = false
            return
        }
        
        do {
            let result = try await authService.signInWithEmail(
                email: emailCredentials.email,
                password: emailCredentials.password
            )
            print("BBBB \(result.user.isEmailVerified)")
            if !result.user.isEmailVerified {
                emailVerificationState.credentials = AuthenticationModel.CreateAccountCredentials(
                    email: emailCredentials.email,
                    password: emailCredentials.password
                )
                emailVerificationState.email = emailCredentials.email
                try await result.user.sendEmailVerification()
                emailAuthAlert.message = AppConstants.Alert.Message.format(
                    AppConstants.Alert.Message.emailVerificationSent,
                    with: emailCredentials.email
                )
                emailAuthAlert.showAlert = true
                
            } else {
                handleSuccessfulAuthentication(for: .email)
            }
            
        } catch {
            handleAuthError(error, for: .emailAuth)
        }
        
        isLoading = false
    }

@MainActor
func resetPassword() async {
    isLoading = true
    
    validateResetPasswordEmail()
    
    if resetPasswordCredentials.email.isEmpty {
        resetPasswordValidationState.email = .invalid("Email is required")
        isLoading = false
        return
    }
    
    guard case .valid = resetPasswordValidationState.email else {
        isLoading = false
        return
    }
    
    do {
        try await authService.resetPassword(email: resetPasswordCredentials.email)
        fotPasswordAlert.message = AppConstants.Alert.Message.format(
            AppConstants.Alert.Message.passwordResetSent,
            with: resetPasswordCredentials.email
        )
        
        fotPasswordAlert.showAlert = true
    } catch {
        handleAuthError(error, for: .fotPassword)
    }
    
    isLoading = false
}
Share Improve this question edited Feb 16 at 14:40 Tulon asked Feb 16 at 14:34 TulonTulon 4,1266 gold badges38 silver badges64 bronze badges 3
  • 1 Doesn't the user resetting their password involve them receiving an email with a password-reset link? – Frank van Puffelen Commented Feb 16 at 15:07
  • Yes, Frank, I understand that, in a way, it indicates this email belongs to the same user. The problem is that I register user data in Firestore only when they verify their email or phone number. So, if a user signs up without verifying their email and then uses the "fot password" feature to sign in, they can access the app, but they won't have any corresponding record in Firestore. – Tulon Commented Feb 16 at 15:18
  • That's the issue I'm trying to address. Now I'm thinking that every time I check the verification status of an email at sign-in, I'll first check if the user ID (UUID) already exists. If it doesn't, I'll create it; if it does, I'll update the related information, such as sign-in time and other metadata. You can share your thoughts on this approach if you'd like. Thanks. @FrankvanPuffelen – Tulon Commented Feb 16 at 15:18
Add a comment  | 

1 Answer 1

Reset to default 2

The emailVerified flag in Firebase authentication indicates whether it has been verified that the user owns the email address; nothing more, nothing less. Given that, them clicking the link in a password-reset email verifies that they have access to that email address, so constitutes email verification.

So to your question: yes, it is expected that emailVerified is set to true after the user reset their password through an email-link.


The problem you're having comes from the fact that you're trying to add your own meaning to the emailVerified property, specifically whether you created a document for that user in Firestore.

To prevent this sort of mismatch, I recommend not using emailVerified for this purpose. Rather, whenever you need to load the user's profile document from Firestore, first check if such a document exists, and if not: send them through the registration flow that creates the document.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论