Skip to content

[FirebaseAuth] signIn(withEmail:link:completion:) doesn't work with MFA #7770

@ir77

Description

@ir77

[REQUIRED] Step 1: Describe your environment

  • Xcode version: Version 12.4 (12D4e)
  • Firebase SDK version: 7.8.1
  • Installation method: CocoaPods
  • Firebase Component: Auth

[REQUIRED] Step 2: Describe the problem

Steps to reproduce:

Hello. I'm an iOS developer.
We are using Firebase Auth for new app development. We use the email link authentication method. We are trying to register for multi-factor authentication by phone number after the email link authentication.

The signIn(withEmail:link:completion:) used in this email link login returns the following error when re-logging in after multi-factor registration. (It is expected that the secondFactorRequired error will be returned.)

Error Domain=FIRAuthErrorDomain Code=17999 "An internal error has occurred, print and inspect the error details for more information." UserInfo={FIRAuthErrorUserInfoNameKey=ERROR_INTERNAL_ERROR, NSLocalizedDescription=An internal error has occurred, print and inspect the error details for more information., NSUnderlyingError=0x283de8d80 {Error Domain=FIRAuthInternalErrorDomain Code=3 "(null)" UserInfo={FIRAuthErrorUserInfoDeserializedResponseKey={
    code = 400;
    message = "INVALID_GRANT_TYPE";
    status = "INVALID_ARGUMENT";
}}}}

I would like to know how to avoid this error.

I have tested it several times and found out a few things. If I disable multifactor registration in the user console of the ID platform, I can log in again. I have also confirmed that I can log in after multifactor registration using methods other than email link log-in (ex. signIn(withEmail:password:completion:) ). I have confirmed that this problem does not occur in web SDK.

reference

Relevant Code:

    func signIn(email: String, link: SignInLink) -> AnyPublisher<SignInResult, RepositoryError> {
        return Future<SignInResult, RepositoryError> { (promise) in
            auth.signIn(withEmail: email, link: link.rawValue) { result, error in
                if let error = error as NSError? {
                    if error.code == AuthErrorCode.secondFactorRequired.rawValue,
                       let resolver = error.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as? MultiFactorResolver,
                       let multiFactorInfo = resolver.hints.first as? PhoneMultiFactorInfo {
                        promise(.success(.needVerifyingMFA(resolver: resolver, phoneMultiFactorInfo: multiFactorInfo))) // I'm expecting to get into this line.
                    } else {
                        promise(.failure(.init(firebaseAuthCommonError: error))) // But it actually goes in a line here.
                        return
                    }
                }

                guard let user = result?.user else {
                    promise(.failure(.init(SignInError.noUser)))
                    return
                }

                guard user.multiFactor.enrolledFactors.isEmpty else {
                    promise(.failure(.init(SignInError.mfaError)))
                    return
                }

                promise(.success(.needEnrollingMFA))
            }
        }
        .eraseToAnyPublisher()
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions