Hi guys,
Often we find that permissions to query a given node in the graph is linked back to a common node which is being checked for permissions.
As an example, let’s take this schema:
type Core @auth(query: { rule: """
query ($API_KEY: String!){
queryCore(filter: { apiKey: { eq: $API_KEY } }) {
id
}
}
""" }){
id: ID!
apiKey: String! @id
children: [Middle]
}
type Middle @auth(rule: """
query ($API_KEY: String!){
queryMiddle {
parent(filter: { apiKey: { eq: $API_KEY } }) {
id
}
}
}
"""){
parent: Core! @hasInverse(field: children)
children: [Lower]
}
type Lower @auth(rule: """
query ($API_KEY: String!){
queryLower {
parent
parent(filter: { apiKey: { eq: $API_KEY } }) {
id
}
}
}
}
"""){
parent: Middle! @hasInverse(field: children)
}
The fact that we have to repeat the same rules for accessing the ‘Core’ node is creating complexities and repeated code, which when you have multiple paths that a request can be authorised for a given node, becomes rather a serious issue.
If the end result in GraphQL needs to be represented this way to process the requests efficiently or in parallel, that’s fine, but having to redefine the same rules over and over again across hundreds of nodes is becoming tedious and really prone to human error.
I have tried changing the schema to the following to try to have Dgraph ‘honour’ the rules of the core node, but all it does is restrict the returning of that core node as a child of a query request for, lets say, the Middle node (i.e. if you request the Middle node with its ‘parent’ Core node, it will stop the Core node from returning, but it won’t stop the Middle node from returning):
type Core @auth(query: { rule: """
query ($API_KEY: String!){
queryCore(filter: { apiKey: { eq: $API_KEY } }) {
id
}
}
""" }){
id: ID!
apiKey: String! @id
children: [Middle]
}
type Middle @auth(rule: """
query (){
queryMiddle {
parent {
id
}
}
}
"""){
parent: Core! @hasInverse(field: children)
children: [Lower]
}
type Lower @auth(rule: """
query ($API_KEY: String!){
queryLower {
parent
parent {
id
}
}
}
}
"""){
parent: Middle! @hasInverse(field: children)
}
I understand how this can become an optimisation issue as trying to have the @auth
rules respect each other may become complex, however, the @auth
queries are being validated when trying to update the schema, so presumably, that point in the process could ‘expand’ the given @auth
rule to respect the @auth
rules of the linked entity as well.
I hope I’m being clear here, but in some way, I’d appreciate a way to not have to repeat myself in the schema, redefining the same rules over and over again; all I should need to do is define rules with variables in the entry point where required, and then in all other places, provided I want the engine to respect the rules of that entity through graph traversal, provide a path for the engine to take to ‘get’ to another entity.
I imagine this could be done by expanding the auth rules of a given type to take into account the rules of linked entities if those paths are provided in the auth rule (e.g., in my above schema, do not return a Middle or Lower node if the request does not also honour the auth rules of the Core node).
Let me know your thoughts; I’m open to dealing with this in any way that avoid repetition of code.