Allowing to choose AND or OR (or XOR) rule for @auth directives implemented from interface

Problem

I have an interface IProtect which adds an array of Permission to implementing types. This way I’m able to write auth rules based on the permissions someone possesses or not.

What I would have liked to do was something like this, that you can define how the rules of the interface should be applied ( @auth(rule: OR)(…) ):

interface IProtect
  @auth(
    query: {
      # System Admins (JWT:{ "ADMIN": "TRUE"}) can query it.
      { rule: "{ $ADMIN: { eq: \"TRUE\"} }" }
    },
    add: {
       # System Admins (JWT:{ "ADMIN": "TRUE"}) can add.
      { rule: "{ $ADMIN: { eq: \"TRUE\"} }" }
    }
  )
{
  permissions: [Permission]!
}

# This won't work since there isn't any (rule: ...) definition for auth directives! 
type Questionnaire implements IProtect
  @auth(rule: OR)(
    query: 
        # or, Users with the permission { rule: READ, scope:Questionnaire} can query it.
        {
          rule: """
          query ($USER:ID!){
            queryQuestionnaire(filter:{has:permissions}){
              permissions(filter:{ has:roles, and: {rule:READ, scope:Questionnaire} }){
                name
                scope
                rule
                roles(filter:{has:users}) {
                  users(filter:{id:[$USER]}){
                    id
                  }
                }
              }
            }
          }
          """
        }
    add:
        # or, User has to have write permission for scope QUESTIONNAIRE.
        {
          rule: """
          query ($USER: ID!) {
            queryQuestionnaire(filter:{has:permissions}){
              permissions(filter:{ has:roles, and: {rule:WRITE, scope:QUESTIONNAIRE} }){
                name
                scope
                rule
                roles(filter:{has:users}) {
                  users(filter:{id:[$USER]}){
                    id
                  }
                }
              }
            }
          }
          """
        }
  ) {
  id: ID!
  publisher: Company!
  name: String!
  version: String
  description: String!
  sections: [Section]! @hasInverse(field: questionnaire)
  tags: [String]
}

Why, in short…

I wanted to add basically “a God mode” to enable anyone with the JWT claim { “ADMIN”: “TRUE” } to do whatever they want. To do this, I have to add this rule to every types @auth directives in an OR clause. I cannot add this rule only to the interface since the auth rules on the interface are implemented with the AND rule.

This means that the user has to be an admin AND the auth rules on the implementing type itself must work out as well… which is not what we want.

What I’m currently doing to make this work (adding the “god mode” on every type):

interface IProtect
{
  permissions: [Permission]!
}

type Questionnaire implements IProtect
  @auth(
    query: {
      or: [
        # System Admins (JWT:{ "ADMIN": "TRUE"}) can query it.
        { rule: "{ $ADMIN: { eq: \"TRUE\"} }" }
        # or, Users with the permission { rule: READ, scope:Questionnaire} can query it.
        {
          rule: """
          query ($USER:ID!){
            queryQuestionnaire(filter:{has:permissions}){
              permissions(filter:{ has:roles, and: {rule:READ, scope:Questionnaire} }){
                name
                scope
                rule
                roles(filter:{has:users}) {
                  users(filter:{id:[$USER]}){
                    id
                  }
                }
              }
            }
          }
          """
        }
      ]
    }
    add: {
        {
          or: [
            # System Admins (JWT:{ "ADMIN": "TRUE"}) can add it.
            { rule: "{ $ADMIN: { eq: \"TRUE\"} }" }
            # or, User has to have write permission for scope QUESTIONNAIRE.
            {
              rule: """
              query ($USER: ID!) {
                queryQuestionnaire(filter:{has:permissions}){
                  permissions(filter:{ has:roles, and: {rule:WRITE, scope:QUESTIONNAIRE} }){
                    name
                    scope
                    rule
                    roles(filter:{has:users}) {
                      users(filter:{id:[$USER]}){
                        id
                      }
                    }
                  }
                }
              }
              """
            }
          ]
        }
  ) {
  id: ID!
  publisher: Company!
  name: String!
  version: String
  description: String!
  sections: [Section]! @hasInverse(field: questionnaire)
  tags: [String]
}

Requested Feature

Allowing to choose how the @auth rules are applied on the implementing types. Being able to choose between AND/OR is a necessity in my opinion, I am not sure about XOR.

4 Likes