Best way to have user-specific data?

We have data that should only be visible to the user that owns the data. Call them notes. Many users where each has access to many notes. Users own their own notes and do not share them with other users.

I see this could be accomplished using queries. The user would query notes using their user ID. The query handler would only respond with user’s own data and the access request would check the query user ID to confirm it equals their token user ID.

The other option I see would be for the user request each note by ID (possibly using nested resources to make this more convenient). This allows the access call to check the user’s access to each note individually.

Is there currently a recommended method for having user-specific data? Is there another method I didn’t mention here? I’m leaning towards queries as they seem simpler, though this will add a little overhead for events.

Hi! And welcome to the forum.

Yes, absolutely possible. But queries are not your best choice. I think you are looking for indirect access.

First of all, I assume your users are authenticated somehow. A JWT token, or something. That you have made an auth call and sent a token event which may contain a user ID or something? If not, then this is where we should start :slight_smile:

Anyway.

Let’s say you want some resources:

http://localhost/api/notekeeper/note/12345
http://localhost/api/notekeeper/user/42

Or as resource IDs, that would be:

notekeeper.note.12345
notekeeper.user.42.notes

Where notekeeper is the name of the service, and notekeeper.user.42.notes is a collection of references to the notes (eg. notekeeper.note.12345) that only user 42 should have access to. Eg. :

{
    { "rid": "notekeeper.note.12345" },
    { "rid": "notekeeper.note.12346" }
}

Indirect access

Resgate only sends an access request for the subscribed resource, and will then assume indirect access to any referenced resource (recursively). This means that you can:

  1. deny access ({ "get":false }) to all individual notes in the response to the access request
  2. verify the access request to notekeeper.user.42.notes by checking the 42 in the resource ID matches the user ID you have in the token.
  3. Now that the user fetches its own list, it will get (indirect) access to all its own notes.

Just a note. This means that a user cannot access individual notes. But if that is needed, this can easily be solved by also having the access request handler for the individual notes verify if the user has access, instead of just saying “access denied” to everything.

Hope that helps.

/Samuel

1 Like

Thanks Samuel, that helps a lot!

I didn’t know that nested resources would inherit access from their parents, that’s cool! Indirect access, is that talked about in the docs?

Am I right that in my get.notekeeper.note.* handler, I’ll have to make individual database queries for each note rather than being able to query all of the notes by user ID? Many more round trips to the database it would seem.

Erm. No. :grimacing: It can be implicity derived from the specs. But, I don’t think it is explicity mentioned anywhere. So it really should be added to the Access control doc page.

Assumingly you want the individual notes to be models that can be updated in real-time, Resgate will perform individual fetches for each, yes. In many cases, this will not be an issue. But it depends on DB. For a embedded key-value store, it is a non-issue. For a SQL DB it may as well be.

If it becomes a performance issue, you can add a cache to your service, so that when you fetch the list of notes in get.notekeeper.user.42, you also fetch note data and store it in a cache which the notekeeper.note.* uses (with and on cache-miss, the data is fetched from the DB).

/Samuel