skip to Main Content

I have integrated a payment system to my Firebase app and their system sends a POST request to my backend. I handle that request as below:

app.post("/subscription", (req, res) => {
  const {data, signature} = req.body;
  const decodedJson = JSON.parse(Buffer.from(data, "base64"));
  return admin
      .firestore()
      .collection("subscriptions")
      .doc(decodedJson.order_id)
      .set({
        subscriptionDate: admin.firestore.FieldValue.serverTimestamp()})
      .then(() => {
        return res.status(200).send("Subscription created");
      })
      .catch((error) => {
        throw new Error(error);
      });
});

Then I have another function that is triggered whenever a new document is created under "subscriptions" collection:

exports.checkPaymentStatus = functions.firestore
    .document("subscriptions/{subscriptionId}")
    .onCreate((snap, context) => {
        return axios.post("https://paymentsystem.com/api/1/get-status", {
          data: dataParam,
          signature: signature,
        })
        .then((response) => {
          if (response.data.status === "success") {
            const batch = admin.firestore().batch();

            batch.update(admin.firestore().collection("subscriptions")
            .doc(snap.id), {subscriberId: context.auth.uid});

            batch.update(admin.firestore().collection("users")
            .doc(context.auth.uid), {
              isPro: true,
              subscribedDate: admin.firestore.FieldValue.serverTimestamp(),
            });
            }
          })
        .catch((error) => {
          console.error("Error occurred:", error);
          });
      });

However, it gives error "Error occurred: TypeError: Cannot read properties of undefined (reading ‘uid’)". It is due to context.auth.uid variable. How can I solve this?

I try to update the field value of user document. But, I need to access user document.

2

Answers


  1. According to the docs:

    EventContext.auth Authentication information for the user that
    triggered the function.

    This object contains uid and token properties for authenticated users.
    For more detail including token keys, see the security rules
    reference.

    This field is only populated for Realtime Database triggers and
    Callable functions. For an unauthenticated user, this field is null.
    For Firebase admin users and event types that do not provide user
    information, this field does not exist.

    In your case it seems you are using Firestore and not Realtime database, so the auth object would be null, you can either using snap.id or pass an id as a document property and then access it using the following: snap.data().id

    Login or Signup to reply.
  2. You’re using gen 1 Cloud Functions triggers for Firestore, and there is no context.auth parameter available in those. See:

    If you migrate the code to gen 2 of Cloud Functions, the information about the user who triggered the function is actually available for the onDocument...WithAuthContext trigger. I recommend having a look at the documentation on Cloud Firestore function triggers and Access user authentication information, which also contain this code sample.

    import { onDocumentWrittenWithAuthContext } from "firebase-functions/v2/firestore"
    
    exports.syncUser = onDocumentWrittenWithAuthContext("users/{userId}", (event) => {
        const snapshot = event.data.after;
        if (!snapshot) {
            console.log("No data associated with the event");
            return;
        }
        const data = snapshot.data();
    
        // retrieve auth context from event
        const { authType, authId } = event;
    
        let verified = false;
        if (authType === "system") {
          // system-generated users are automatically verified
          verified = true;
        } else if (authType === "unknown" || authType === "unauthenticated") {
          // admin users from a specific domain are verified
          if (authId.endsWith("@example.com")) {
            verified = true;
          }
        }
    
        return data.after.ref.set({
            created_by: authId,
            verified,
        }, {merge: true}); 
    }); 
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search