Skip to content

fix(auth, android): surface the error code when getIdToken() fails - #18605

Open
dyt9120 wants to merge 1 commit into
firebase:mainfrom
dyt9120:fix/auth-android-getidtoken-error-code
Open

fix(auth, android): surface the error code when getIdToken() fails#18605
dyt9120 wants to merge 1 commit into
firebase:mainfrom
dyt9120:fix/auth-android-getidtoken-error-code

Conversation

@dyt9120

@dyt9120 dyt9120 commented Aug 22, 2026

Copy link
Copy Markdown

Description

On Android, a token refresh the backend refuses — the account was disabled or deleted, or its refresh token revoked — reaches Dart from User.getIdToken() / getIdTokenResult() as [firebase_auth/unknown] (message The user's credential is no longer valid. The user must sign in again. or The user account has been disabled by an administrator.) instead of user-token-expired / user-not-found / user-disabled, the codes iOS and web produce for the same situation. An app that branches on the code to sign a dead session out never sees it on Android.

Cause. Since #11362, getIdToken awaits the native Task with Tasks.await(), which reports a failed Task as a java.util.concurrent.ExecutionException wrapping the Task's own exception. FlutterFirebaseAuthPluginException.parserExceptionToFlutter only reads the error code off the exception it is handed (nativeException is FirebaseAuthException), so the wrapped FirebaseAuthInvalidUserException is never looked at and code stays UNKNOWN. The three network-ish arms already check cause, which is why network-request-failed survived that change and the auth codes did not.

Fix. Unwrap an ExecutionException to its cause before classifying. getIdToken is the only Tasks.await call site in the plugin, so this is the only path affected. The message is unchanged — it already came from the cause through ExecutionException.getMessage() and the Dart side's split(': ').last — only the code changes.

Verified on an Android 13 (API 33) emulator against the Auth emulator: disabling the signed-in account behind its back and forcing a refresh yields user-disabled with this change and unknown without it. The added e2e test (firebase_auth_user_e2e_test.dart, getIdToken() group) does the same through the existing emulatorDisableUser helper; it passes on iOS and web today and fails on Android without the fix.

Related Issues

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]).
This will ensure a smooth and quick review process. Updating the pubspec.yaml and changelogs is not required.

  • 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 (See Contributor Guide).
  • All existing and new tests are passing. — The new test's flow was verified by hand on the Android emulator (above); I have not run the full e2e suite locally and am relying on CI for it.
  • I updated/added relevant documentation (doc comments with ///). — none needed; the change is internal to the Android plugin.
  • The analyzer (melos run analyze) does not report any problems on my PR. — not run locally (sparse checkout); the only Dart change is one e2e test written in the surrounding file's style.
  • I read and followed the Flutter Style Guide.
  • I signed the CLA. — will complete when the CLA check asks.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Does your PR require plugin users to manually update their apps to accommodate your change?

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

`getIdToken()` awaits the native Task with `Tasks.await()` (since firebase#11362),
which reports a failed Task as an `ExecutionException` wrapping the Task's
own exception. `parserExceptionToFlutter` only read the error code off the
exception it was handed, so every refused refresh — a disabled or deleted
account, a revoked token — reached Dart as `[firebase_auth/unknown]` with
the message "The user's credential is no longer valid. The user must sign
in again.", instead of `user-disabled`, `user-not-found` or
`user-token-expired`, the codes the other platforms produce (the
`[firebase_auth/unknown]` seen in firebase#18561 is this).

Unwrap the `ExecutionException` to its cause before classifying, and add an
e2e test that disables the signed-in account behind its back and expects
`user-disabled` from a forced refresh.
@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 Aug 22, 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.

@SelaseKay

Copy link
Copy Markdown
Contributor

Hi @dyt9120, thanks for the contribution. This LGTM! Kindly sign CLA and resolve the formatting issues in ci so I can approve. Thanks

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