Skip to content

[firebase_auth]: iOS Sign in with Apple discards the native NSError domain/code — unrecognised ASAuthorization failures all surface as "unknown / An unknown error has occurred." #18413

Description

@bjrochem72

Is there an existing issue for this?

  • I have searched the existing issues.

Closest prior art, none of which covers this: #10055 (user cancel used to surface as unknown — fixed by typing it as canceled), #18172 (overlapping Apple requests — fixed in 6.4.0 by serialising and typing operation-not-allowed), #17813 (same surface symptom, closed as an app configuration error). This issue is about the remaining fall-through branch, which still destroys the error information.

Which plugins are affected?

Auth

Which platforms are affected?

iOS

Description

On iOS, signInWithProvider(AppleAuthProvider()) runs Sign in with Apple natively via the plugin's own ASAuthorizationController. When the flow fails, authorizationController:didCompleteWithError: maps the four typed ASAuthorizationError codes (1001 canceled, 1002 invalid-response, 1003 not-handled, 1004 failed) to useful Flutter error codes — but ASAuthorizationErrorUnknown (1000) and every other NSError domain fall through to convertToFlutterError:, which only extracts a code when FIRAuthErrorUserInfoNameKey is present. Native AuthenticationServices/AuthKit errors never carry that key, so the Dart side receives the literal fallback:

[firebase_auth/unknown] An unknown error has occurred.

NSError.domain, NSError.code, and any NSUnderlyingError are discarded. The only place the real error survives is the plugin's own NSLog(@"Sign in with Apple errored: %@", error) — visible in the Xcode console, unreachable in production.

Why this matters in production: fleet monitoring on a shipping app shows real users failing Sign in with Apple in under 500 ms with this opaque error. From Dart it is impossible to distinguish, for example:

  • com.apple.AuthenticationServices.AuthorizationError Code=1000 — commonly a device with no usable Apple ID session (user signed out of iCloud, restricted/managed Apple ID), where the right response is a targeted "check you're signed in to your Apple ID in Settings" message;
  • AKAuthenticationError Code=-7026 ("Told not to present authorization sheet") — a presentation conflict, where a retry works;
  • anything else Apple decides to throw.

Cancellation (#10055) and request overlap (#18172) were both fixed by surfacing what actually happened; this fall-through branch is the last place where the information is destroyed instead.

Proposal — keep code: "unknown" for backward compatibility, but stop discarding the native identity. Something like:

case ASAuthorizationErrorUnknown:
default: {
  NSError *underlying = error.userInfo[NSUnderlyingErrorKey];
  NSString *detail =
      [NSString stringWithFormat:@"%@ (Domain=%@ Code=%ld%@)",
                                 error.localizedDescription.length > 0
                                     ? error.localizedDescription
                                     : @"An unknown error has occurred.",
                                 error.domain, (long)error.code,
                                 underlying == nil
                                     ? @""
                                     : [NSString stringWithFormat:
                                           @", Underlying: Domain=%@ Code=%ld",
                                           underlying.domain, (long)underlying.code]];
  completion(nil, [FlutterError errorWithCode:@"unknown" message:detail details:nil]);
  break;
}

(Equally happy with the domain/code going into details instead of the message if that's preferred.) I'm willing to submit a PR if maintainers agree with the direction.

Reproducing the issue

  1. On a physical device, sign out of the Apple Account (Settings → sign out), or use any device state where AuthenticationServices refuses the request without presenting the sheet.
  2. Call FirebaseAuth.instance.signInWithProvider(AppleAuthProvider()).
  3. The call fails immediately. The Xcode console shows the full NSError via the plugin's NSLog; Dart receives only [firebase_auth/unknown] An unknown error has occurred. with no way to recover the domain/code.

Any unrecognised ASAuthorizationController delegate error takes the same path.

Firebase Core version

4.11.0

Flutter Version

3.44.4 (stable)

Relevant Log Output

# Xcode console — the information that never reaches Dart:
Sign in with Apple errored: Error Domain=com.apple.AuthenticationServices.AuthorizationError Code=1000 "(null)"

# What Dart receives:
FirebaseAuthException([firebase_auth/unknown] An unknown error has occurred.)

Flutter dependencies

Expand Flutter dependencies snippet
firebase_core: 4.11.0
firebase_auth: 6.5.4
firebase_ui_auth: 3.0.1
firebase_ui_oauth_apple: 2.0.1

Additional context and comments

The typed ladder in didCompleteWithError has improved case by case (canceled in #10055's fix, operation-not-allowed via #18172) precisely because each shape became distinguishable. This change would do the same for the remaining bucket: everything currently labelled unknown would still be unknown, but carry Domain=… Code=… so apps can classify (the message format is already parseable the same way as the Code: N pattern some FIRAuth errors embed).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs AttentionThis issue needs maintainer attention.platform: iosIssues / PRs which are specifically for iOS.plugin: authtype: bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions