firebase / firebase-ios-sdk

Firebase SDK for Apple App Development
https://firebase.google.com
Apache License 2.0
5.56k stars 1.45k forks source link

[Auth]: `credential` property is not set for 'emailAlreadyInUse' errors #13671

Open michaelowolf opened 1 day ago

michaelowolf commented 1 day ago

Description

I've raised an equivalent issue against Flutterfire at https://github.com/firebase/flutterfire/issues/13268, where most of the detail can be found.

The gist of the issue is that the docs for Flutter suggest that we should be able to retrieve a credential property from the exception when an email is already in use (see https://pub.dev/documentation/firebase_auth/latest/firebase_auth/User/linkWithProvider.html). This is true for web and Android, but not for iOS. As far as I can tell, this means we don't have a way of recovering from this error for a user on iOS without asking them to sign in again.

I expect the relevant piece of code for the iOS SDK is at: https://github.com/firebase/firebase-ios-sdk/blob/936ddf44f84238713beef4b73ec138e92ba93b89/FirebaseAuth/Sources/Swift/Utilities/AuthErrorUtils.swift#L290 (where no credential is appended to the error).

Reproducing the issue

I don't have means to reproduce this exclusively for the iOS SDK, but reproduction steps for the Flutter SDK can be found at https://github.com/firebase/flutterfire/issues/13268.

Firebase SDK Version

11.0.0

Xcode Version

15.4

Installation Method

CocoaPods

Firebase Product(s)

Authentication, Crashlytics

Targeted Platforms

iOS

Relevant Log Output

No response

If using Swift Package Manager, the project's Package.resolved

Expand Package.resolved snippet
```json Replace this line with the contents of your Package.resolved. ```

If using CocoaPods, the project's Podfile.lock

Expand Podfile.lock snippet
```yml PODS: - AppAuth (1.7.5): - AppAuth/Core (= 1.7.5) - AppAuth/ExternalUserAgent (= 1.7.5) - AppAuth/Core (1.7.5) - AppAuth/ExternalUserAgent (1.7.5): - AppAuth/Core - Firebase/Auth (11.0.0): - Firebase/CoreOnly - FirebaseAuth (~> 11.0.0) - Firebase/CoreOnly (11.0.0): - FirebaseCore (= 11.0.0) - Firebase/Crashlytics (11.0.0): - Firebase/CoreOnly - FirebaseCrashlytics (~> 11.0.0) - firebase_auth (5.3.0): - Firebase/Auth (= 11.0.0) - firebase_core - Flutter - firebase_core (3.5.0): - Firebase/CoreOnly (= 11.0.0) - Flutter - firebase_crashlytics (4.1.2): - Firebase/Crashlytics (= 11.0.0) - firebase_core - Flutter - FirebaseAppCheckInterop (11.2.0) - FirebaseAuth (11.0.0): - FirebaseAppCheckInterop (~> 11.0) - FirebaseAuthInterop (~> 11.0) - FirebaseCore (~> 11.0) - FirebaseCoreExtension (~> 11.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.0) - GoogleUtilities/Environment (~> 8.0) - GTMSessionFetcher/Core (~> 3.4) - RecaptchaInterop (~> 100.0) - FirebaseAuthInterop (11.2.0) - FirebaseCore (11.0.0): - FirebaseCoreInternal (~> 11.0) - GoogleUtilities/Environment (~> 8.0) - GoogleUtilities/Logger (~> 8.0) - FirebaseCoreExtension (11.2.0): - FirebaseCore (~> 11.0) - FirebaseCoreInternal (11.2.0): - "GoogleUtilities/NSData+zlib (~> 8.0)" - FirebaseCrashlytics (11.0.0): - FirebaseCore (~> 11.0) - FirebaseInstallations (~> 11.0) - FirebaseRemoteConfigInterop (~> 11.0) - FirebaseSessions (~> 11.0) - GoogleDataTransport (~> 10.0) - GoogleUtilities/Environment (~> 8.0) - nanopb (~> 3.30910.0) - PromisesObjC (~> 2.4) - FirebaseInstallations (11.2.0): - FirebaseCore (~> 11.0) - GoogleUtilities/Environment (~> 8.0) - GoogleUtilities/UserDefaults (~> 8.0) - PromisesObjC (~> 2.4) - FirebaseRemoteConfigInterop (11.2.0) - FirebaseSessions (11.2.0): - FirebaseCore (~> 11.0) - FirebaseCoreExtension (~> 11.0) - FirebaseInstallations (~> 11.0) - GoogleDataTransport (~> 10.0) - GoogleUtilities/Environment (~> 8.0) - GoogleUtilities/UserDefaults (~> 8.0) - nanopb (~> 3.30910.0) - PromisesSwift (~> 2.1) - Flutter (1.0.0) - fluttertoast (0.0.2): - Flutter - Toast - google_sign_in_ios (0.0.1): - AppAuth (>= 1.7.4) - Flutter - FlutterMacOS - GoogleSignIn (~> 7.1) - GTMSessionFetcher (>= 3.4.0) - GoogleDataTransport (10.1.0): - nanopb (~> 3.30910.0) - PromisesObjC (~> 2.4) - GoogleSignIn (7.1.0): - AppAuth (< 2.0, >= 1.7.3) - GTMAppAuth (< 5.0, >= 4.1.1) - GTMSessionFetcher/Core (~> 3.3) - GoogleUtilities/AppDelegateSwizzler (8.0.2): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - GoogleUtilities/Privacy - GoogleUtilities/Environment (8.0.2): - GoogleUtilities/Privacy - GoogleUtilities/Logger (8.0.2): - GoogleUtilities/Environment - GoogleUtilities/Privacy - GoogleUtilities/Network (8.0.2): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Privacy - GoogleUtilities/Reachability - "GoogleUtilities/NSData+zlib (8.0.2)": - GoogleUtilities/Privacy - GoogleUtilities/Privacy (8.0.2) - GoogleUtilities/Reachability (8.0.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - GoogleUtilities/UserDefaults (8.0.2): - GoogleUtilities/Logger - GoogleUtilities/Privacy - GTMAppAuth (4.1.1): - AppAuth/Core (~> 1.7) - GTMSessionFetcher/Core (< 4.0, >= 3.3) - GTMSessionFetcher (3.5.0): - GTMSessionFetcher/Full (= 3.5.0) - GTMSessionFetcher/Core (3.5.0) - GTMSessionFetcher/Full (3.5.0): - GTMSessionFetcher/Core - nanopb (3.30910.0): - nanopb/decode (= 3.30910.0) - nanopb/encode (= 3.30910.0) - nanopb/decode (3.30910.0) - nanopb/encode (3.30910.0) - package_info_plus (0.4.5): - Flutter - pointer_interceptor_ios (0.0.1): - Flutter - PromisesObjC (2.4.0) - PromisesSwift (2.4.0): - PromisesObjC (= 2.4.0) - RecaptchaInterop (100.0.0) - Toast (4.1.1) - url_launcher_ios (0.0.1): - Flutter - webview_flutter_wkwebview (0.0.1): - Flutter - FlutterMacOS DEPENDENCIES: - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`) - Flutter (from `Flutter`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) SPEC REPOS: trunk: - AppAuth - Firebase - FirebaseAppCheckInterop - FirebaseAuth - FirebaseAuthInterop - FirebaseCore - FirebaseCoreExtension - FirebaseCoreInternal - FirebaseCrashlytics - FirebaseInstallations - FirebaseRemoteConfigInterop - FirebaseSessions - GoogleDataTransport - GoogleSignIn - GoogleUtilities - GTMAppAuth - GTMSessionFetcher - nanopb - PromisesObjC - PromisesSwift - RecaptchaInterop - Toast EXTERNAL SOURCES: firebase_auth: :path: ".symlinks/plugins/firebase_auth/ios" firebase_core: :path: ".symlinks/plugins/firebase_core/ios" firebase_crashlytics: :path: ".symlinks/plugins/firebase_crashlytics/ios" Flutter: :path: Flutter fluttertoast: :path: ".symlinks/plugins/fluttertoast/ios" google_sign_in_ios: :path: ".symlinks/plugins/google_sign_in_ios/darwin" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" pointer_interceptor_ios: :path: ".symlinks/plugins/pointer_interceptor_ios/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" webview_flutter_wkwebview: :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" SPEC CHECKSUMS: AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa Firebase: 9f574c08c2396885b5e7e100ed4293d956218af9 firebase_auth: f27287630c4d9e2c3c63e64d9240822ad6b07e5b firebase_core: 2ec6b789859c7c24766344ec71fdf78639402d56 firebase_crashlytics: 60630a0f91ee432275fa1660fd8593079761448a FirebaseAppCheckInterop: ea21450529cf0ebd132788dd8916a0269abc684f FirebaseAuth: d5cf28be74d7e82257f6a3f717509eff70d3cf4a FirebaseAuthInterop: 47c09558af5d1b31f16fb352387c72d4804f4a24 FirebaseCore: 3cf438f431f18c12cdf2aaf64434648b63f7e383 FirebaseCoreExtension: cda74ddfb001224bd8fd1d6e74698b4ed07803de FirebaseCoreInternal: 0c569513412da9f3b31bd0b340013bbee8f295c5 FirebaseCrashlytics: 745d8f0221fe49c62865391d1bf56f5a12eeec0b FirebaseInstallations: 771177d89d6c451dc6e50085ec82e2fc77ed0a4a FirebaseRemoteConfigInterop: 477b26fdeb8fb5fbaf22fa9db5343b42289dc7db FirebaseSessions: adcec8b72d0066a385e3affcd1bcb1ebb3908ce6 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c google_sign_in_ios: 07375bfbf2620bc93a602c0e27160d6afc6ead38 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c pointer_interceptor_ios: 508241697ff0947f853c061945a8b822463947c1 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 RecaptchaInterop: 7d1a4a01a6b2cb1610a47ef3f85f0c411434cb21 Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4 PODFILE CHECKSUM: a57f30d18f102dd3ce366b1d62a55ecbef2158e5 COCOAPODS: 1.15.2 ```
google-oss-bot commented 1 day ago

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

paulb777 commented 1 day ago

I started investigating and the issue seems to go beyond the SDK and I don't see what the other platforms are doing differently.

The backend doesn't return anything beyond that there is an EMAIL_EXISTS error.

(lldb) po decodedDictionary 
▿ 1 element
  ▿ 0 : 2 elements
    - key : "error"
    ▿ value : AnyHashable([AnyHashable("code"): AnyHashable(400), AnyHashable("message"): AnyHashable("EMAIL_EXISTS"), AnyHashable("errors"): AnyHashable([AnyHashable([AnyHashable("message"): AnyHashable("EMAIL_EXISTS"), AnyHashable("domain"): AnyHashable("global"), AnyHashable("reason"): AnyHashable("invalid")])])])
      ▿ value : 3 elements
        ▿ 0 : 2 elements
          ▿ key : AnyHashable("code")
            - value : "code"
          ▿ value : AnyHashable(400)
            - value : 400
        ▿ 1 : 2 elements
          ▿ key : AnyHashable("message")
            - value : "message"
          ▿ value : AnyHashable("EMAIL_EXISTS")
            - value : "EMAIL_EXISTS"
        ▿ 2 : 2 elements
          ▿ key : AnyHashable("errors")
            - value : "errors"
          ▿ value : AnyHashable([AnyHashable([AnyHashable("message"): AnyHashable("EMAIL_EXISTS"), AnyHashable("domain"): AnyHashable("global"), AnyHashable("reason"): AnyHashable("invalid")])])
            ▿ value : 1 element
              ▿ 0 : AnyHashable([AnyHashable("message"): AnyHashable("EMAIL_EXISTS"), AnyHashable("domain"): AnyHashable("global"), AnyHashable("reason"): AnyHashable("invalid")])
                ▿ value : 3 elements
                  ▿ 0 : 2 elements
                    ▿ key : AnyHashable("message")
                      - value : "message"
                    ▿ value : AnyHashable("EMAIL_EXISTS")
                      - value : "EMAIL_EXISTS"
                  ▿ 1 : 2 elements
                    ▿ key : AnyHashable("domain")
                      - value : "domain"
                    ▿ value : AnyHashable("global")
                      - value : "global"
                  ▿ 2 : 2 elements
                    ▿ key : AnyHashable("reason")
                      - value : "reason"
                    ▿ value : AnyHashable("invalid")
                      - value : "invalid"