How to pass arguments from Dart to Cloud functions written in Typescript and it also gives me error code UNAUTHENTICATED

1,694

Solution 1

You have created a database trigger, what you should do is create a callable function as shown below

exports.sendToDevice = functions.https.onCall(async (data, context) => {
    const payload: admin.messaging.MessagingPayload = {
        notification: {
          title: 'Dummy title',
          body: `Dummy body`,
          click_action: 'FLUTTER_NOTIFICATION_CLICK'
        }
      };

      return await fcm.sendToDevice(data.token, payload);
  });

Solution 2

Your Flutter side of code seems right, what's wrong is on the Cloud Function.

The sendToDevice function is not a callable function. It is a Cloud Firestore Triggers, it is only meant to be automatically called whenever a document matches users/{uid} is created.

Instead, you'll want to create a Callable Function, see below

export const sendToDevice = functions.https
  .onCall(async (data) => {
    const { token } = data; // Data is what you'd send from callable.call

    const payload: admin.messaging.MessagingPayload = {
      notification: {
        title: 'Dummy title',
        body: `Dummy body`,
        click_action: 'FLUTTER_NOTIFICATION_CLICK'
      }
    };

    return fcm.sendToDevice(token, payload);
  }
);
Share:
1,694
iDecode
Author by

iDecode

When developers want to hide something from you, they put it in docs.

Updated on December 19, 2022

Comments

  • iDecode
    iDecode over 1 year

    Dart function (passing token to sendToDevice):

    Future<void> _sendNotification() async {
      CloudFunctions functions = CloudFunctions.instance;
      HttpsCallable callable = functions.getHttpsCallable(functionName: "sendToDevice");
    
      callable.call({
        'token': await FirebaseMessaging().getToken(),
      });
    }
    

    index.ts file where I have defined sendToDevice method.

    import * as functions from 'firebase-functions';
    import * as admin from 'firebase-admin';
    admin.initializeApp();
    
    const fcm = admin.messaging();
    
    export const sendToDevice = functions.firestore
      .document('users/uid')
      .onCreate(async snapshot => {
    
        const payload: admin.messaging.MessagingPayload = {
          notification: {
            title: 'Dummy title',
            body: `Dummy body`,
            click_action: 'FLUTTER_NOTIFICATION_CLICK'
          }
        };
    
        return fcm.sendToDevice(tokens, payload); // how to get tokens here passed from above function?
      }
    );
    

    Questions:

    1. How can I receive tokens passed from my Dart function _sendNotification to Typescript's sendToDevice function.

    2. When I was directly passing tokens inside index.ts file, I was getting this exception:

    [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(functionsError, Cloud function failed with exception., {code: UNAUTHENTICATED, details: null, message: UNAUTHENTICATED})

    Can anyone please explain if I am supposed to authenticate something here? The command firebase login shows I am already signed in. I am very new to Typescript so please bear with these stupid questions.

    • Stewie Griffin
      Stewie Griffin almost 4 years
      Are you trying to get this function triggered when a new document is created? If so, why are you calling the same function from client side again?
    • iDecode
      iDecode almost 4 years
      @StewieGriffin Yes actually that's what I am looking for, since I have no idea bout typscript, not sure what this code is doing.
    • Stewie Griffin
      Stewie Griffin almost 4 years
      So then you should store your device tokens on your db to query them when function is triggered, not passing them from the client side to the function. The flow should be like this: a document is created -> cloud function is triggered -> function queries tokens from db -> it pushes notifications
  • iDecode
    iDecode almost 4 years
    Thank you for your suggestion, but sorry they weren't quite useful. For instance, you said getHttpsCallable should be triggered by https, can you please tell me where inside my code am I supposed to make that change?
  • iDecode
    iDecode almost 4 years
    Second, the example you provided doesn't reveal how they are handling passed parameter inside index.js file, they only provided Dart code and my code resembles to it, can you please tell me how can I do that inside index.js?
  • vitooh
    vitooh almost 4 years
    Sorry @iKeepChangingName I thought it's clear, I added the reference to Google Documentation, I hope it will help you!
  • iDecode
    iDecode almost 4 years
    Thank you for your answer, I am using your code, but I getting this error Unhandled Exception: PlatformException(functionsError, Cloud function failed with exception., {code: UNAUTHENTICATED, details: null, message: UNAUTHENTICATED}), I double checked my token isn't null.
  • Yaobin Then
    Yaobin Then almost 4 years
    In that case, I'd suggest a few debugging steps just to be sure, first, double check that your credentials are on the same Firebase project. Secondly, remove the FCM portion just to test the function is called. Access to your Firebase console and try to send a notification using the token you've gotten. You might also want to see what's logging on the Cloud Function Dashboard