Unable to access custom_user_data

I’ve added a couple of questions surrounding the authentication element of Atlas Device Sync previously and everyone has been really helpful but for whatever reason, what I believe from my reading that I need to do has not actually worked and I’ve needed a lot of assistance to get things over the line.

I have a mobile app that I am wanting to develop. This mobile app will give me a JWT and I will use custom JWT authentication to authenticate into my Realm DB sync.

I have now enabled “custom user data” and mapped that to a UserId field in my Mongo document:

{
  "_id": {
    "$binary": {
      "base64": "VngS3zFmSyK0K6emoxYXHg==",
      "subType": "04"
    }
  },
  "Organisations": [
    {
      "OrganisationId": 17,
      "AppPermission": true
    },
    {
      "OrganisationId": 18,
      "AppPermission": false
    },
    {
      "OrganisationId": 19,
      "AppPermission": true
    }
  ],
  "Name": "Chris Boot",
  "UserId": "567812df-3166-4b22-b42b-a7a6a316171e"
}```

However, I can never see this data and it always comes back as null. 

My use case here is that based on who is logged in is what data gets downloaded to the device so if a user has access to organisation 17 and 19 in the app (which is aluded to in the demo snippet above) and the best way I see of doing this is using custom user data and then if that user has permissions revoked / added this will update the data on their device.

As ever, any assistance is very appreciated.

Hi, I believe the confusion might be in the mapping. The idea is that the field you link to “UserId” should be the App Services UserId, such that the service will take the ID that it knows about, lookup the data in your cluster for the user with that id, and then bundle it into the user object to be used within permission evaluation. The internal user_id is a stringified version of a MongoDB ObjectID, but here you have the value with a UUID (which seems to indicate that it is where things are not matching up).

Let me know if that makes sense and seems to solve your issues.

Best,
Tyler

Hi Tyler,

Apologies for coming back time and again here but I’m still not able to get this working and this is clearly a fundamental misunderstanding on my part and I’m spending weeks trying to make something work and I think last time it was a bit of luck and not knowledge that got my over the line.

I’m setting up rules and filters and going into custom user auth elements and regardless of what I change I get all data coming down from my database into my Realm, there is no filtering going on no matter what I setup and configure.

I copied and pasted one of the rules up from the document but this just said it was incompatible with the sync.

Are there any video walkthroughs or similar for this that I am also able to view as this may help me understand the bits that I’m missing.

Thanks

I tend to find that this is the best guide for permissions: https://www.mongodb.com/docs/atlas/app-services/sync/app-builder/device-sync-permissions-guide/

If you want to send me a link to your application in the Atlas UI I can take a look as well.

As a note, filters are not supported for Device Sync. You can / should use Document Permissions in the role to accomplish the same thing.

Best,
Tyler

Thanks Tyler,

That is really helpful - I copied a rule and managed to prove off one element of what I wanted to do which was to filter based on a single field - that’s great. This means that can be my starting point for any rules going forward.

The complexity I currently can’t make work is the custom user information - I don’t know how to send a link to my application but I have granted permission for Mongo to access my infrastructure. The organisation id: 5d0bbbf5cf09a218fdd59326 and the project is bootcom evacuation.

The rule is in there but I can’t get this working for custom user data. Any tips would be extremely welcome.

Chris

Great, I have found your application. Things seem to be set up properly (rule looks good and the orgId is a queryable field).

Can you please send me the UserId of a user that you are testing with (I see a few in the logs that seem like they are working properly as we see this in the logs)

[
  "Roles selected for sync:",
  "   owner-read-write: [ Person ]",
  "   readAndWriteAll: [ Evacuation ]"
]

Can you explain more about what you are expecting to see (I see no failed writes). I suspect the issue then is that you are expecting data to be returned but it is not. In that case, can you confirm the contents of the user document for that user_id?

Well the fact it appears to be setup correctly fills me with hope! Thanks Tyler

I have modified my rule from the following:

{
  "roles": [
    {
  "name": "owner-read-write",
  "apply_when": {},
  "document_filters": {
    "read": { "orgId": "20" },
    "write": { "orgId": "20" }
  },
  "read": true,
  "write": true
}
  ]
}

to:

{
  "roles": [
    {
  "name": "owner-read-write",
  "apply_when": {},
  "document_filters": {
    "read": { "orgId": { "$in" : "%%user.custom_data.EvacOrganisations" } },
    "write": { "orgId": { "$in" : "%%user.custom_data.EvacOrganisations" } }
  },
  "read": true,
  "write": true
}
  ]
}

My user document is as follows:

image

The JWT decodes to the following so I can see all the details are correct:

{
  "email": "demo@demo.com",
  "unique_name": "demo account",
  "nameid": "567812df-3166-4b22-b42b-a7a6a316171e",
  "sub": "567812df-3166-4b22-b42b-a7a6a316171e",
  "customUserId": "567812df-3166-4b22-b42b-a7a6a316171e",
  "nbf": 1722964835,
  "exp": 1722965735,
  "iat": 1722964835,
  "iss": "DEMO_ISSUER",
  "aud": "DEMO_AUDIENCE"
}

The main problem here is that when I start my .net application and the Realm is invoked I get the following:

Realms.Exceptions.RealmException: ‘A system error occurred while operating on a Realm. See InnerException for more details.’

Where the inner exception is:

ArgumentException: Invalid query Logs: App Services

The URL I go to has no errors, this is my problem.

Chris

To update, if I try doing this via the Realm application I get the following exception:

ending session with error: evaluating permissions failed: failed to prepare permissions for table “Person”: document filters did not pass validation: $in needs an array (ProtocolErrorCode=206)

Got it, yeah it looks like this is the error in the backend that we captured (We should forward this to the logs you are able to view)

failed to prepare permissions for table "Person": document filters did not pass validation: $in needs an array``

This means that the rule attempted to expand "%%user.custom_data.EvacOrganisations" but did not find any data. I suspect that the issue is that the system cannot find the custom data because the mapping is not correct. One way to confirm this is to add something like this into the apply_when expression and I suspect you will find that the role is not selected (meaning that the custom_user is not available to the system). "%%user.custom_data": { "$exists": true }

I think the issue is that in the configuration, you are telling App Services that each user document has an _id field that maps to the app services user_id, but that is not present in the document you shared above.

I will admit it is a touch confusing, but there is an internal user_id concept. This is what you see when you go to the users tab in App Services and it is a MongoDB ObjectId (in string form) that is a unique identifier to a specific App Services user. See here: App Services

When setting up custom user data, you are telling us that for that user_id, there is a document in X collection where the value of field Y is the internal user_id.

So the system is looking up db.AppUsers.find({_id: "666ca19606b6e2fd82c6cc84"}) and it is not finding anything because you have configured the user document to have an ID that is a UUID and not anything the system knows about.

This is why I linked the documentation above https://www.mongodb.com/docs/atlas/app-services/users/custom-metadata/#custom-user-data

The key is that App Services has a user_id and you own the collection of user data, on the configuration page for custom user data, you are telling us, how we should search through the custom user data to find the document that pertains to a user_id (that is the only thing we know at that time)

Hope this is helpful,
Tyler

Thanks for this, I’ve put in the “apply_when” element so my rule is now the following which I believe is what you were alluding to:

{
  "roles": [
    {
      "name": "owner-read-write",
      "apply_when": {
        "%%user.custom_data": {
          "$exists": true
        }
      },
      "document_filters": {
        "write": {
          "orgId": {
            "$in": "%%user.custom_data.EvacOrganisations"
          }
        },
        "read": {
          "orgId": {
            "$in": "%%user.custom_data.EvacOrganisations"
          }
        }
      },
      "read": true,
      "write": true
    }
  ]
}

Running this through Realm and checking the logs I still get the following:

ending session with error: evaluating permissions failed: failed to prepare permissions for table “Person”: document filters did not pass validation: $in needs an array (ProtocolErrorCode=206)

I intentionally modified my identifier in the appusers collection to be a string and not a UUID / object id so all types matched and I could rule that out as a problem. Originally it was a UUID but I’ve modified it (this was yesterday so shouldn’t have caused any issues today).

In my app I run the following .net code:

var doc = user.GetCustomData();

And this returns null also - so the custom user object must exist but not have a value.

I’ll continue to look at the matching for custom user data and see whether there is anything I can do in the interim.

Ok, modified that to:

{
  "%%user.custom_data": {
    "$ne": null
  }
}

Which gave the result you expected so it’s not matching that data.

I intentionally modified my identifier in the appusers collection to be a string and not a UUID / object id so all types matched and I could rule that out as a problem

Yes, but my point is that the UUID / String-version-of-it is your concept of the user_id. Device sync and App Services has its own concept of user_id (something to uniquely identify a user). If you check the users page I linked to above you should see it. It is a hex-encoder MongoDB Object-ID.

So the way you have configured things is that we go to lookup data at the user_id that App Services knows about but it does not find a match, because you are having it point to the _id field that is a different concept entirely from the user_id that App Services uses.

What you need is to add a field to the custom data documents that has the value of the app services user_id field. It can be the _id, but if not you can name it mongo_user_id (or whatever you want), update the custom user data configuration to point to that field as the “mapping”, and then ensure that anything that inserts data into that function uses the App Services user_id.

Note that the user_id is present in all functions https://www.mongodb.com/docs/atlas/app-services/functions/context/#get-user-data--context.user-

Also, you can configure a function to run each time a user is created and then you can have it go insert a document into that collection. See here for that: https://www.mongodb.com/docs/atlas/app-services/users/custom-metadata/#user-creation-function

Best,
Tyler

Ok, I think I get that.

Mongo provides its own user id field which is absolutely fine and I saw this in my .net MAUI app so the question here then is how I get that user Id into a different users record - how is the problem generally solved is really what I probably need to look at next (which in your previous message has been pointing me to the user creation function which I shyed away from because I already have the user)

1 Like

Hi Tyler, this has all worked fine and I’ve managed to pull down data successfully (I tested multiple times to make sure I’ve not just got lucky and I think I’m there).

I have a couple of other things I want to check out which I may have follow up questions on but I’d like to thank you for walking me through this.

All working and all good (thanks again Tyler!)

Awesome, glad you got everything working!

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.