Skip to content

fix(auth, iOS): guard URL handlers when no FirebaseApp is configured - #18641

Open
jobweegink wants to merge 1 commit into
firebase:mainfrom
jobweegink:fix/auth-ios-url-handlers-guard
Open

fix(auth, iOS): guard URL handlers when no FirebaseApp is configured#18641
jobweegink wants to merge 1 commit into
firebase:mainfrom
jobweegink:fix/auth-ios-url-handlers-guard

Conversation

@jobweegink

Copy link
Copy Markdown

Description

FLTFirebaseAuthPlugin (iOS) handles incoming URLs in application(_:open:options:) and scene(_:openURLContexts:) by calling Auth.auth() unconditionally. When the default FirebaseApp has not been configured yet, Auth.auth() hits FirebaseAuth's fatal error

The default FirebaseApp instance must be configured before the default Auth instance can be initialized

and the process dies on any URL delivered through one of the app's CFBundleURLSchemes.

This happens in apps that initialise Firebase from Dart with explicit FirebaseOptions (no GoogleService-Info.plist) some time after start-up — e.g. after reading which environment to use from local storage — and in debug/test binaries that never call Firebase.initializeApp at all. In both cases the plugin is still registered as an app/scene lifecycle delegate and receives the URL.

ensureAPNSTokenSetting() in the same file already guards with FirebaseApp.app() != nil. This PR applies the same guard to the two URL handlers: when no app is configured they return false (not handled) instead of trapping.

Reproduction (firebase_auth 6.6.1, iOS 26 simulator): a CFBundleURLTypes entry with a custom scheme, no GoogleService-Info.plist, Firebase.initializeApp not yet called, then xcrun simctl openurl booted "<scheme>:///x" → crash in scene(_:openURLContexts:) (Auth.swift:151, FLTFirebaseAuthPlugin.swift:194).

Related Issues

None found for this exact trap; happy to link one if maintainers know of it.

Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • My PR includes unit or integration tests for all changed/updated/fixed behaviors — the change is a two-line guard in native iOS lifecycle-delegate code; there is no existing harness for delivering a URL before FirebaseApp.configure. I can add one if you point me at the right place.
  • All existing and new tests are passing.
  • I updated/added relevant documentation (doc comments with ///).
  • The analyzer (melos run analyze) does not report any problems on my PR.
  • I read and followed the Flutter Style Guide.
  • I signed the CLA.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

  • Yes, this is a breaking change.
  • No, this is not a breaking change.

`application(_:open:options:)` and `scene(_:openURLContexts:)` call `Auth.auth()` unconditionally. When the default FirebaseApp has not been configured yet (an app that calls `Firebase.initializeApp` from Dart with explicit options after start-up, or a debug build that never initialises Firebase), `Auth.auth()` hits FirebaseAuth's fatal "The default FirebaseApp instance must be configured before the default Auth instance can be initialized" and the process dies on any URL delivered through the app's URL schemes.

`ensureAPNSTokenSetting()` in the same file already guards with `FirebaseApp.app() != nil`; this applies the same guard to the two URL handlers, returning `false` (not handled) when no app is configured.
@gemini-code-assist

Copy link
Copy Markdown
Contributor
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

@google-cla

google-cla Bot commented Sep 3, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@russellwheatley russellwheatley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracking this down, the repro steps are clear and the guard matches the pattern ensureAPNSTokenSetting() already uses in this file.

Left two suggestions: logging a debug-only breadcrumb when a URL gets silently dropped, so it's easier to notice in dev builds if this path fires and a real deep link ends up going nowhere.

Also, the CLA check is currently failing, could you sign it at https://cla.developers.google.com/ so this can get merged? 🙏

Comment on lines +189 to +192
// Auth.auth() traps when no FirebaseApp has been configured yet (e.g. an
// app that initialises Firebase from Dart-side options after start-up).
guard FirebaseApp.app() != nil else { return false }
return Auth.auth().canHandle(url)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth a debug-only log here so it's visible during development that a URL got dropped because Firebase wasn't configured yet.

Suggested change
// Auth.auth() traps when no FirebaseApp has been configured yet (e.g. an
// app that initialises Firebase from Dart-side options after start-up).
guard FirebaseApp.app() != nil else { return false }
return Auth.auth().canHandle(url)
// Auth.auth() traps when no FirebaseApp has been configured yet (e.g. an
// app that initialises Firebase from Dart-side options after start-up).
guard FirebaseApp.app() != nil else {
#if DEBUG
print(
"[firebase_auth] Ignoring URL because no FirebaseApp is configured yet. " +
"Call Firebase.initializeApp() before this URL is delivered if Auth should handle it."
)
#endif
return false
}
return Auth.auth().canHandle(url)


public func scene(_ scene: UIScene, openURLContexts urlContexts: Set<UIOpenURLContext>) -> Bool
{
guard FirebaseApp.app() != nil else { return false }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here for consistency with the other handler.

Suggested change
guard FirebaseApp.app() != nil else { return false }
guard FirebaseApp.app() != nil else {
#if DEBUG
print(
"[firebase_auth] Ignoring URL because no FirebaseApp is configured yet. " +
"Call Firebase.initializeApp() before this URL is delivered if Auth should handle it."
)
#endif
return false
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants