Skip to content

onCall Cloud Function returns 'unauthenticated' for anonymous user despite client sending a valid ID Token on macOS. #17660

@hyakarun

Description

@hyakarun

Is there an existing issue for this?

  • I have searched the existing issues.

Which plugins are affected?

Cloud Functions, Core

Which platforms are affected?

macOS

Description

onCall Cloud Function returns 'unauthenticated' for anonymoususer despite client sending a valid ID Token on macOS.

Reproducing the issue

  1. [Bug] Step to Reproduce

  2. Initialize a Flutter app on macOS with Firebase and enable Anonymous
    Authentication.

  3. Sign in a user anonymously using
    FirebaseAuth.instance.signInAnonymously().

  4. Confirm the sign-in is successful and a FirebaseUser object is
    created.

  5. Immediately before calling the function, force-refresh the ID token:
    await FirebaseAuth.instance.currentUser?.getIdTokenResult(true);

  6. Call a callable Cloud Function using
    FirebaseFunctions.instanceFor(region:
    'us-central1').httpsCallable('yourFunctionName');

  7. [Bug] Expected Behavior

The context.auth object in the onCall function should be populated
with the anonymous user's authentication data, and the function should
execute successfully.

  1. [Bug] Actual Behavior

The onCall function returns a FirebaseFunctionsException with the code
unauthenticated and the message "The function must be called while
authenticated."

This happens despite the client app successfully obtaining a valid ID
token immediately before the call. We have confirmed this with the
following logs, which show a valid token being printed right before
the error occurs:

1 flutter: Firebase ID Token: eyJhbGciOiJSUzI1Ni... (A valid
JWT)
2 flutter: Token Expiration: 2025-08-26 00:37:37.000
3 flutter: StickerShopPage: Attempting to purchase sheetId: 8
4 flutter: Cloud Function error: unauthenticated - The function
must be called while authenticated.

Firebase Core version

4.0.0

Flutter Version

3.35.1

Relevant Log Output

1         flutter: Firebase ID Token: eyJhbGciOiJSUzI1Ni... (A
     valid JWT)
   2         flutter: Token Expiration: 2025-08-26 00:37:37.000
   3         flutter: StickerShopPage: Attempting to purchase
     sheetId: 8
   4         flutter: Cloud Function error: unauthenticated - The
     function must be called while authenticated.

Flutter dependencies

[!] Flutter (Channel stable, 3.35.1, on macOS 15.6 24G84 darwin-arm64, locale
ja-JP) [635ms]
• Flutter version 3.35.1 on channel stable at
/Users/mukulogi/Documents/flutter
! Warning: dart on your path resolves to
/opt/homebrew/share/flutter/bin/dart, which is not inside your current
Flutter SDK checkout at /Users/mukulogi/Documents/flutter. Consider adding
/Users/mukulogi/Documents/flutter/bin to the front of your path.
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 20f8274939 (11 days ago), 2025-08-14 10:53:09 -0700
• Engine revision 1e9a811bf8
• Dart version 3.9.0
• DevTools version 2.48.0
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop,
enable-windows-desktop, enable-android, enable-ios, cli-animations,
enable-lldb-debugging
• If those were intentional, you can disregard the above warnings; however
it is recommended to use "git" directly to perform update checks and
upgrades.

[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0)
[77.7s]
• Android SDK at /Users/mukulogi/Library/Android/sdk
• Emulator version 35.6.11.0 (build_id 13610412) (CL:N/A)
• Platform android-36, build-tools 36.0.0
• Java binary at: /Applications/Android
Studio.app/Contents/jbr/Contents/Home/bin/java
This is the JDK bundled with the latest Android Studio installation on
this machine.
To manually set the JDK path, use: flutter config --jdk-dir="path/to/jdk".
• Java version OpenJDK Runtime Environment (build 21.0.6+-13391695-b895.109)
• All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 16.4) [1,435ms]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 16F6
• CocoaPods version 1.16.2

[✓] Chrome - develop for the web [9ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2025.1) [8ms]
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 21.0.6+-13391695-b895.109)

[✓] VS Code (version 1.102.2) [7ms]
• VS Code at /Users/mukulogi/Downloads/Visual Studio Code.app/Contents
• Flutter extension version 3.116.0

[✓] Connected device (2 available) [6.9s]
• macOS (desktop) • macos • darwin-arm64 • macOS 15.6 24G84 darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 139.0.7258.139

[✓] Network resources [2.4s]
• All expected network resources are available.

! Doctor found issues in 1 category.

  • firebase_core version: ^4.0.0
    * cloud_functions version: ^6.0.0
    * firebase_auth version: ^6.0.1

Additional context and comments

Additionally, firebase_auth is also affected as it is
responsible for anonymous sign-in and ID token generation,
which are central to this issue.

  1. [Bug] Additional Context We have performed an exhaustive debugging process and have confirmed
    the following:

    • Server-side code is correct: The Cloud Function is a standard onCall
      function that correctly checks if (!context.auth).
    • Client-side code is correct: The Flutter app uses httpsCallable to
      invoke the function.
    • Region is correct: Both the client and the deployed function are
      configured for us-central1.
    • Deployment is correct: We have run firebase deploy --only functions
      and confirmed via the CLI that the latest onCall code is deployed on
      the server.
    • No Emulators: The app is connecting directly to the production
      Firebase backend.
    • IAM Permissions: The function has been configured to "Allow
      unauthenticated invocations" at the Google Cloud IAM level.
    • Server-side Debug Logs: We added console.log statements to the Cloud
      Function to check if context.auth is present. However, these debug
      logs never appeared in the Cloud Functions logs, even after ensuring
      the IAM permissions were set to allow unauthenticated invocations.
      This indicates the function's code is not even being reached,
      suggesting a blocking issue at the Firebase infrastructure level.

The core of the issue is that the Firebase backend infrastructure is not
correctly populating the context.auth object from the valid ID token
provided by the Flutter client SDK on the macOS platform, or is blocking
the invocation entirely before the function code executes.

Code Snippets

Client-side call in Flutter:

1 // Service that calls the function
2 Future<void> purchaseStickerSheetWithCF(String sheetId) 
  async {
3   final user = FirebaseAuth.instance.currentUser;
4   if (user == null) {
5     throw Exception("User not authenticated to call 
  function");
6   }
7 
8   final callable = FirebaseFunctions.instanceFor(region:
  'us-central1')
9       .httpsCallable('purchaseStickerSheet');

10
11 try {
12 // This call fails with an 'unauthenticated' error
13 await callable.call<Map<String, dynamic>>({'sheetId':
sheetId});
14 } on FirebaseFunctionsException catch (e) {
15 print("Cloud Function error: ${e.code} - ${e.message}");
16 rethrow;
17 }
18 }
19
20 // Widget code that triggers the call
21 onPressed: () async {
22 // We log the token here to prove it exists and is valid
23 final idTokenResult = await
FirebaseAuth.instance.currentUser?.getIdTokenResult(true);
24 if (idTokenResult != null) {
25 print('Firebase ID Token: ${idTokenResult.token}');
26 }
27 // The call is made right after getting the token
28 await
_firestoreService.purchaseStickerSheetWithCF(sticker.shopIte
mId.toString());
29 }

Server-side Cloud Function (index.js):

1 exports.purchaseStickerSheet = functions.https.onCall(async
  (data, context) => {
2   console.log("DEBUG: Cloud Function received call."); // 
  Added for debugging
3   if (context.auth) {
4     console.log("DEBUG: context.auth is present! UID:",
  context.auth.uid); // Added for debugging
5     console.log("DEBUG: context.auth.token (payload):",
  context.auth.token); // Added for debugging
6   } else {
7     console.log("DEBUG: context.auth is NULL. Token 
  verification failed."); // Added for debugging
8     throw new functions.https.HttpsError(
9         "unauthenticated",

10 "The function must be called while authenticated.",
11 );
12 }
13
14 const userId = context.auth.uid;
15 const sheetId = data.sheetId;
16
17 // ... function logic
18 });

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions