Can't Update Node to Create Edge Due to Auth Rules

Report a GraphQL Bug

Not really a bug, just a weird limitation that needs resolved

Can’t Update Node to Create Edge unless auth rules allow updating both nodes.

What edition and version of Dgraph are you using?

Edition:

  • SlashGraphQL
  • Dgraph (community edition/Dgraph Cloud)

If you are using the community edition or enterprise edition of Dgraph, please list the version:

Dgraph Version
v20.11.0-11-gb36b4862

Have you tried reproducing the issue with the latest release?

No, but expect same results.

Steps to reproduce the issue (paste the query/schema if possible)

type User @auth(
  # user `me` can query own user but not update/add/delete
) {
  username: String! @id
  isActive: boolean
  plan: String
  isContact: Contact! @hasInverse(field: "isUser")
  starredContacts: [Contact] @hasInverse(field: "starredBy")
}
type Contact @auth(
  # user `me` has full access to contacts to query/add/update/delete
) {
  id: ID
  name: String!
  isUser: User
  starredBy: [User]
}
mutation starContact {
  updateContact(input: {
    filter: { id: ["0x7"] }
    set: { starredBy: [{ username: "me" }] }
  }) {
    numUids
    contact {
      id
      starredBy(filter: { username: { eq: "me" } }) { username }
    }
  }
}

Expected behaviour and actual result.

Expected - starredBy to be updated on the Contact
data: {
  updateContact: {
    numUids: 1
    contact: [
      {
        id: "0x7",
        starredBy: [
          {
            username: "me"
          }
        ]
      }
    ]
  }
}
Results - starredBy not updated on the Contact
data: {
  updateContact: {
    numUids: 1 # odd returning 1 here
    contact: [
      {
        id: "0x7",
        starredBy: [] # but nothing here
      }
    ]
  }
}

Why that wasn’t great, with examples

I want to control access not allowing a user to update their own user, and would also like to prevent a user from updating the User <User.isContact> Contact edge, but I need to allow a user to update the Contact <Contact.starredBy> User to their own user, but not anybody else.

I think I could work around this by removing the inverse relationship on the User → starredContacts edge, but then I have no way of getting all of the contacts a user has starred since I have no other way to filter root nodes by an edge other than cascade which is not very efficient.

Another use similar use case would be creating a friendRequest between two contacts where a user has permission to update only one contact but the inverse relationship on the other contact for requested friendships should also be updated.

2 Likes

Well, if I would pay closer attention to what I was doing, I would notice that I was seeing the opposite effect if I actually used the correct mutation, :man_facepalming:

But the opposite of this is still true, so I think this should remain open to tighten up the restrictions in a controlled way.

Actual results is that even if I don’t have update access to both nodes I can still create an edge between them and the inverse edge would also be made if I have update access to at least one of them.

In the examples above, I could not update the User to create the edge, but I could update the Contact to make the edge. This would mean, I could also delete/create the edge between User.isContact to Contact.isUser which I want to lock down and restrict unless I have update access to both nodes.

2 Likes