Access based on originalDoc data

default discord avatar
chladog
last year
1 1

I'm in need of access control (per field and per collection) that is based on the collection item's originalDoc.
I have a collection Posts where any logged in user can create a Post. However User should be able to read, update and delete only his own Post.
There should be also possible to restrict certain fields that would be editable only by system or admins, not Users.
I have implemented a relationship field owner, relatedTo Users. I used afterChange (operation===create) on Post to fill the value automatically by the system.

Now I need to write an access functions that will resolve true only if user.id === doc.owner. I stuck here as access functions don't pass doc data.
I tried to leverage different hooks but it feels hacky and I got inconsistent or weird results.
With read op for example filtering out not-owned items in Posts with beforeRead query returns totalDocs of all Posts in the system and lists all posts, just those not-owned are null.

With update op I didn't even find a combination of hooks that would make such access control possible (even if there is any it feels like wrong unmaintainable approach).

I understand that current access implementation is only for controlling access in whole collection based on user and input data. Any suggestions how to go about this? If this is not currently possible, would it make sense to introduce such features?

  • discord user avatar
    jmikrut
    Payload Team
    last year

    Hey @chladog — question for you.

    When you say:

    Now I need to write an access functions that will resolve true only if user.id === doc.owner. I stuck here as access functions don't pass doc data.

    Do you want to use field hooks, or collection-level hooks here?

    If collection level, this is actually super easy. In access control, you can return a query constraint to restrict which documents that a user can perform actions against.

    Here's an example of how we would normally do something like this:

    const adminOwnerAccess = ({ req: { user } }) => {
      // If user is admin, return true
      if (user && user.roles.includes('admin')) {
        return true;
      }
    
      // If there is a user, return a query constraint
      // that only allows users to perform actions against
      // documents where the owner is equal to their user ID
      if (user) {
        return {
          owner: {
            equals: user.id,
          },
        };
      }
    
      // If neither of the above conditions are met,
      // Block access
      return false;
    };

    Is this what you need? Note, we might need to expand on our docs if you didn't see that this is possible via documentation. It's one of the strongest features of our access control!

    3 replies
  • default discord avatar
    chladog
    last year

    oh, right! I even had it implemented similiary in other collection already facepalm.

    Though how to implement same logic with FieldAccess?
    My collection has following structure:

    {
    owner: User
    editors: User[],
    someData: {
         ...
    }

    Required behavior is that User who is an Owner or one of the Editors can update the document (solved already by query constraint).
    But only Owner can change Owner and Editors field.
    Editor can change everything except Owner and Editors.

  • discord user avatar
    jmikrut
    Payload Team
    last year

    OK I just released payload@0.14.30-beta.0 which now includes doc in the field access function arguments for both read and update operations.

    You can read whatever you want off that original doc. But note that the doc is only available in read and update operations, as there will be no doc in create. There, you'll need to check the incoming data property due to the document just recently having been created.

    How's that? Give it a shot!

  • default discord avatar
    chladog
    last year

    Working like a charm. Perfect, thank you!

Open the post
Continue the discussion in GitHub
Like what we're doing?
Star us on GitHub!

Star

Connect with the Payload Community on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.