question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

FCM SendAllAsync not working with Google Application Default Credentials

See original GitHub issue

Environment

  • Operating System version: Mac OS Catalina (10.15.7)
  • Firebase SDK version: 2.0.0
  • Firebase Product: Firebase Cloud Messaging
  • .NET version: .NET Core 3.1
  • OS: Mac

The problem

We’re developing a .NET Core API for a new mobile applicatione. One of the features is sending Push Notifications from the API. To make connection with all our Google Services and Firebase Cloud Messaging we’re making use of APPLICATION DEFAULT CREDENTIALS. This is not done via a environment variable but with logging in with following command.

gcloud auth application-default login

When doing the initial setup we encountered a problem that had the following error message.

FirebaseAdmin.Messaging.FirebaseMessagingException: 
Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the fcm.googleapis.com. 
We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. 
For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/.

Eventually this problem was resolved by setting the billing/quota_project in my config by running following command.

gcloud auth application-default set-quota-project my-project

Sending single push notifications was no problem and everything was implemented very quickly.

Now we were up to sending push notifications to a batch of devices (tokens). Therefore we are using the method SendMulticastAsync to send a single message to different devices, underlying this method is using SendAllAsync.

When we implemented this in our API we noticed that none of the messages was sent. When digging a bit deeper we saw that the reason for this was following error which is the same as we encountered during setup. The strange thing is that the single notification is still working.

FirebaseAdmin.Messaging.FirebaseMessagingException: 
Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the fcm.googleapis.com. 
We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. 
For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/.

I already pulled my hair out finding the solution for this but after hours of searching didn’t came up with a solution. No idea if I’m doing something wrong or there’s some bug. But I do hope you guys can help out 😃

Relevant Code:

// Startup.cs

FirebaseApp.Create(new AppOptions
{
    Credential = GoogleCredential.GetApplicationDefault(),
    ProjectId = configuration.GetValue<string>("Firebase:ProjectId")
});
// Implementation

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FirebaseAdmin.Messaging;
using MyProject.Domain.CloudMessaging;

namespace MyProject.Infrastructure.Firebase
{
    public class CloudMessagingService : ICloudMessagingService
    {
        public async Task SendSingleNotification(NotificationData notificationData, string token)
        {
            if (token == null)
            {
                return;
            }

            var message = CreateMessage(notificationData, token);

            try
            {
                await FirebaseMessaging.DefaultInstance.SendAsync(message);
            }
            catch (Exception e)
            {
                Console.Write(e);
            }
        }

        public async Task SendMultipleNotifications(NotificationData notificationData, List<string> tokens)
        {
            if (tokens.Count == 0)
            {
                return;
            }

            var message = CreateMulticastMessage(notificationData, tokens);

            try
            {
                var response = await FirebaseMessaging.DefaultInstance.SendMulticastAsync(message);
                Console.WriteLine($"{response.SuccessCount} messages were sent successfully");
            }
            catch (Exception e)
            {
                Console.Write(e);
            }
        }

        private Message CreateMessage(NotificationData notificationData, string token)
        {
            var message = new Message
            {
                Notification = new Notification
                {
                    Title = notificationData.Title,
                    Body = notificationData.Body
                },
                Data = notificationData.Data,
                Token = token,
                FcmOptions = new FcmOptions
                {
                    AnalyticsLabel = notificationData.AnalyticsLabel.ToString()
                }
            };

            return message;
        }

        private MulticastMessage CreateMulticastMessage(NotificationData notificationData, IReadOnlyList<string> tokens)
        {
            var message = new MulticastMessage
            {
                Notification = new Notification
                {
                    Title = notificationData.Title,
                    Body = notificationData.Body
                },
                Data = notificationData.Data,
                Tokens = tokens
            };

            return message;
        }
    }
}

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
jonasgoderiscommented, Jan 4, 2021

@DamienDoumer thank you for your advice regarding how to send messages to several users, will definitely take a look into that! Much appreciated!

Just wondering then in which case(s) the method SendMulticastAsync should be used then?

0reactions
hiranya911commented, Jan 5, 2021

Just catching up to this issue. Here are my thoughts on this:

  1. We generally discourage developers from using end user credentials (EUC) to authorize the Admin SDK. There are a number of APIs that don’t work with EUC, and it seems the FCM batch API is one of them. We recommend developers to use service accounts with the GOOGLE_APPLICATION_CREDENTIALS environment variable to get app default credentials working locally (see https://firebase.google.com/docs/admin/setup#initialize-sdk).
  2. It is a little strange that the regular FCM API accepts EUC+quota_project, but the batch API doesn’t. @chong-shao you might want to look into that separately. But it’s not a high priority.

Update: Also note that for this use case to work as intended, you might have to set the quota project on the GoogleCredential object it self. See https://github.com/googleapis/google-api-dotnet-client/blob/master/Src/Support/Google.Apis.Auth/OAuth2/GoogleCredential.cs#L296-L307

Read more comments on GitHub >

github_iconTop Results From Across the Web

Application Default Credentials Not Working in Cloud ...
I am trying to use the service account using Google Cloud Functions to access the Workspace Directory API. I am trying to use...
Read more >
Firebase Admin Java SDK Release Notes - Google
Fixed an issue in the Authentication API to correctly set the emulator credentials ... This initializes an app using Google Application Default Credentials, ......
Read more >
FirebaseAdmin.Messaging.FirebaseMessaging Class ...
Gets the messaging instance associated with the default Firebase app. This property is null if the default app doesn't yet exist.
Read more >
Google Cloud Function: Could not load the default ...
This issue occurs due to many reasons and the solution may vary based on that, You can try using gcloud auth application-default login...
Read more >
Firebase Cloud Messaging by Using C#
Firebase Cloud Messaging, aka FCM is a cross-platform messaging solution that ... it will be signed a [Default] name. var app = Credential....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found