Payload.body does not appear to be accessible in the auth script

Hello! I am new at Realm and I am trying to achieve the https - function script authentication described by @Pavel_Duchovny in Custom Function authentication and POST method - #11 by Andrea

This is the code I am implementing:

exports = function(payload) {
  const authInput = JSON.parse(payload.body.text());
  
  if (authInput.user_id)
  {
    return authInput.user_id;
  }
};

However, payload.body does not appear to be accessible in the auth script (“TypeError: Cannot access member ‘text’ of undefined”). If I run the same script on the function itself, while authenticating as system, the function works fine and payload.body is accessible and returns the user_id.

Is there something I am missing? thanks in advance.

Hi @Jesus_Santin ,

Its possible that the interface has changed since then.

Have you tried printing payload.text() or just payload?

Maybe its now passed via header only. I need to test.

Thanks
Pavel

Hello @Pavel_Duchovny , thanks for your reply. I have not been able to make it work with the suggestions you have indicated. In any case, I am fairly new and may be doing something wrong.

I take this opportunity to thank you for the content you have published about Appgyver and Realm, its been very useful to me. Greetings,
Jesus Santin

Hello @Jesus_Santin

The way a custom function authentication works could be explained as follows:

I have a custom example payload defined as:

const payload = {
    uid: 100,
    user: "custom_function",
    email: "cf@josman.com",
    name: "custom function",
    provider_type: "custom_function"
}

This is the payload I am going to use for this example user custom_function whenever it needs to authenticate against my Realm Application. I have my own business logic in where every user will have an internal uid that will keep track of every user independently.

When I run the following code in my application:

const credentials = Realm.Credentials.function(payload);

async function authenticate() {
    console.log("AUTHENTICATE");
    try {
        const user = await app.logIn(credentials);
        return user.id;
    } catch (err) {
        console.error(err);
    }
}

What I am doing is authenticating this user against my Realm backend. At this moment, there are two possible scenarios: either the user exists and I am performing a login or the user did not exist in my Realm app and I am registering it for the first time.

My Realm function linked to the Custom Authentication is as follows

exports = async function (loginPayload) {
  console.log(JSON.stringify(loginPayload));

  
  const dbName = context.values.get('db_name');
  const users = context.services.get('mongodb-atlas').db(dbName).collection("Users");
  
  // Parse out custom data from the FunctionCredential
  const { uid } = loginPayload;
  // Query for an existing user document with the specified uid
  const user = await users.findOne({ uid });
  if (user) {
    // If the user document exists, return its unique ID
    return user._id.toString();
  } else {
    // If the user document does not exist, create it and then return its unique ID
    const result = await users.insertOne(loginPayload);
    return result.insertedId.toString();
  }
  
};

This will either create the user or if exist letting them access the app.

I know that your specific example is not exactly the same use case, as you will validate the id as a sort of apiKey but the principle is the same.

In @Pavel example, he is sending the payload in the body of the HTTP request, as you can see in the cURL:

curl \
-H "Content-Type: application/json" \
-d '{"user_id":"5fa7105a871d206bd6739a4", "comment_id" : 1, "post_id" : 1, comment : "great post!" }' \
https://webhooks.mongodb-realm.com/api/client/v2.0/app/app-abcd/service/myTest/incoming_webhook/storeComment

More precisely: -d '{"user_id":"5fa7105a871d206bd6739a4", "comment_id" : 1, "post_id" : 1, comment : "great post!" }'

In both examples, you need to create the payload that you will later on access in your function. If you are getting undefined, it could be that there is a difference between what you are sending and the key you are accessing.

Could you try printing the payload? Add the following to your function:

console.log(payload);

And look in the logs for the information that is stored here to check whether you are accessing the correct key or not.

I hope you found my explanation useful. Please do not hesitate to contact me if you need any further clarification or if you would like to provide us with further details.

Kind Regards,
Josman

Hello @Josman_Perez_Exposit, thank you very much for your explanation :pray:. It helped me a lot to understand how custom authentication script works.

As you suggested, I’ve been testing with console.log and getting different results depending on whether I check it in custom auth script or main function (using system authentication).

If I test console.log(Object.entries(payload)) within the main function and system authentication I receive:

Logs:
[
  "query,[object Object],headers,[object Object],body,[object Binary]"
]```
however when I try the same code in the custom auth script I get:

Logs:
[
“”
]```
I have also tried a few different approaches and always get the same result. Do you think this is the expected behaviour of the script? Is there anything else I need to do to access the body data?

Thanks and happy new year! :slight_smile:

@Josman_Perez_Exposit ,

I think there is a miscommunication here.

In my example I am not using custom authentication per say , I am using the “script” authentication method for functions.

The idea is a script is executed against the webhook call and extract some user id from the call (or potential database).

In my example the userId is passed as part of a comment update payload… It used to work but maybe something has changed , have not got the chance to repro

Thanks