Skip to content

fix(auth, windows): add opt-in flag to skip id-token EventChannel (FAST_FAIL_INVALID_ARG workaround)#18223

Closed
hughesyadaddy wants to merge 1 commit intofirebase:mainfrom
hughesyadaddy:fix/auth-windows-id-token-optin
Closed

fix(auth, windows): add opt-in flag to skip id-token EventChannel (FAST_FAIL_INVALID_ARG workaround)#18223
hughesyadaddy wants to merge 1 commit intofirebase:mainfrom
hughesyadaddy:fix/auth-windows-id-token-optin

Conversation

@hughesyadaddy
Copy link
Copy Markdown

@hughesyadaddy hughesyadaddy commented Apr 23, 2026

Summary

Adds FirebaseAuthPlatform.disableIdTokenChannelOnWindows, an opt-in
static flag that — when set to true before
Firebase.initializeApp() — skips the id-token EventChannel
subscription in MethodChannelFirebaseAuth's constructor on Windows.

Default behavior is unchanged. Linux, macOS, Android, iOS, and Web are
not touched. The flag is a plain static bool so it is reachable
from user code before MethodChannelFirebaseAuth's constructor
runs (any instance-level setter would arrive too late — the listener
is registered the moment FirebaseAuthPlatform.instance is first
accessed).

Fixes #18210. Related: #13340, #16888, #17800, #11933.

Why

The Windows firebase_auth_plugin dispatches id-token events
from a native background thread. Flutter's engine requires platform
channel traffic on the platform thread and raises a
FAST_FAIL_INVALID_ARG (0xc0000409 /
STATUS_STACK_BUFFER_OVERRUN) abort when that contract is violated.
Users hit this as a silent process termination shortly after
signInWithEmailAndPassword() or on cold starts with a cached
refresh token. cdb confirms the crashing frame:

flutter_windows!fml::KillProcess
flutter_windows!fml::LogMessage::~LogMessage
flutter_windows!flutter::PlatformMessageHandlerStandard::InvokeHandler
flutter_windows!flutter::IncomingMessageDispatcher::HandleMessage
firebase_auth_plugin.dll!EventChannel<...>::Send
firebase_auth_plugin.dll!<id-token listener callback>   << wrong thread

The true fix is upstream in the Flutter engine
(flutter/flutter#134346 — open since Sep 2023, currently P2). Until
FlutterDesktopEnginePostPlatformThreadTask (or equivalent) ships
and firebase_auth_desktop adopts it, affected apps have no
supported workaround
: every Dart-side mitigation suggested in the
linked threads (Future.microtask,
WidgetsBinding.addPostFrameCallback, Future.delayed,
runZonedGuarded, custom BinaryMessenger) runs after the native
side has already dispatched from the wrong thread and cannot prevent
the abort. Not subscribing to idTokenChanges() in user code
doesn't help either — the listener is attached unconditionally by the
platform-interface constructor.

This PR gives affected apps an explicit, opt-in escape hatch that:

  • Lives entirely in Dart.
  • Costs nothing at runtime for apps that don't enable it.
  • Is trivially removable once the engine fix lands (delete the flag
    and its one call site).

What changes

  1. FirebaseAuthPlatform.disableIdTokenChannelOnWindows — a new
    static bool field, default false, documented with links to
    the upstream tickets.
  2. MethodChannelFirebaseAuth's constructor — guards the id-token
    EventChannel registration with _shouldSkipIdTokenChannel()
    which only returns true when the flag is set and the host
    is Windows (and not web).
  3. Unit test disable_id_token_channel_on_windows_test.dart
    covering the flag's default and toggle behavior.

No Pigeon, platform-interface-breaking, or generated-code changes.
No CHANGELOG edit — Melos generates that on release from the
conventional commit message.

Scope / trade-offs when the flag is enabled on Windows

Fully unaffected — every imperative API and the most common
observer:

  • All sign-in methods (signInWithEmailAndPassword, signInWithCredential,
    signInWithCustomToken, signInAnonymously, phone, popup, redirect).
  • signOut(), createUserWithEmailAndPassword().
  • authStateChanges() stream — full fidelity (separate channel,
    already dispatched from the platform thread). Fires on sign-in,
    sign-out, and cold-start-with-cached-user.
  • FirebaseAuth.instance.currentUser — populated correctly by
    _handleAuthStateChangesListener and by synchronous assignment
    inside every sign-in method.
  • user.getIdToken() / user.getIdToken(true) /
    user.getIdTokenResult(forceRefresh: true) — imperative RPCs,
    unaffected.
  • All user mutations: updateDisplayName, updateEmail,
    updatePassword, updatePhoneNumber, updateProfile,
    reload, unlink, delete, reauthenticateWithCredential,
    verifyBeforeUpdateEmail, etc.
  • sendPasswordResetEmail, confirmPasswordReset,
    applyActionCode, checkActionCode, verifyPasswordResetCode.
  • MFA, email verification, useAuthEmulator, tenant ID, custom
    auth domain.

Degraded — the real trade-off:

  1. idTokenChanges() stream goes silent on Windows. Never emits —
    not on sign-in, sign-out, token refresh, nor custom-claims updates.
  2. userChanges() stream loses native-driven emissions. It still
    emits when the app itself calls profile-mutation methods
    (updateProfile, updateEmail, reload, etc.) because
    those invoke sendAuthChangesEvent directly. It stops emitting
    from native sources (sign-in/out, token refresh, admin-driven
    custom-claims changes).
  3. Auto-push of admin-side custom-claims updates does not reach the
    client via streams. Workaround: imperatively call
    user.getIdToken(true) when you need fresh claims.

This is strictly better than the current Windows status quo (process
abort on every cached login) for every app that does not rely on live
custom-claims stream notifications — which is most apps.

Test plan

  • flutter test for firebase_auth_platform_interface — all 181
    tests pass, including the 2 new ones in
    disable_id_token_channel_on_windows_test.dart.
  • dart analyze lib test — no issues.
  • dart format --set-exit-if-changed — no diff.
  • Manually reproduced and verified on Windows 10 26200 with
    firebase_auth 6.4.0 / firebase_auth_platform_interface 8.1.9 via a
    local dependency_override:
    • Flag unset (default): 0xc0000409 abort on cached-login cold
      start, reproduced.
    • Flag set before Firebase.initializeApp(): no crash;
      authStateChanges() fires correctly on sign-in, sign-out, and
      cold-start-with-cached-user; app stable for 40s+ of sync traffic.

Usage

import 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  FirebaseAuthPlatform.disableIdTokenChannelOnWindows = true;
  await Firebase.initializeApp(...);
  runApp(...);
}

Follow-up (out of scope for this PR)

Adds FirebaseAuthPlatform.disableIdTokenChannelOnWindows, an opt-in
static flag that — when set to 	rue before Firebase.initializeApp()
— skips the id-token EventChannel subscription in
MethodChannelFirebaseAuth's constructor on Windows.

Default behavior is unchanged. Linux, macOS, Android, iOS, and Web are
not touched.

This is a stopgap workaround for the upstream Windows native threading
bug tracked in firebase#18210 and flutter/flutter#134346:
the native Windows firebase_auth plugin dispatches id-token events
from a background thread, causing the Flutter engine to abort the
process with FAST_FAIL_INVALID_ARG (0xc0000409 /
STATUS_STACK_BUFFER_OVERRUN) shortly after sign-in. Every Dart-side
mitigation suggested in the linked threads runs after the native side
has already dispatched from the wrong thread and cannot prevent the
abort. Affected apps currently have no supported workaround.

Trade-off when enabled on Windows:
 - authStateChanges() — unaffected.
 - idTokenChanges() / userChanges() — still fire on sign-in / sign-out
   (via the separate auth-state channel). Mid-session token-refresh
   events (e.g. custom-claims updates) are not observed until the
   underlying engine fix ships.
 - getIdToken() / getIdTokenResult() — unaffected.

The flag is a temporary mitigation and can be deleted once the engine
fix lands and firebase_auth_desktop adopts a platform-thread dispatch
primitive (see flutter/flutter#134346 comment thread).

Related: firebase#18210, firebase#13340, firebase#16888, firebase#17800, firebase#11933
Made-with: Cursor
@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

Customization

To customize 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 counter productive. 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
Copy link
Copy Markdown

google-cla Bot commented Apr 23, 2026

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.

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.

[firebase_auth]: <still the windows threading bug>

1 participant