Variables in @requireAuth?

We are using Azure AD auth, and I’ve been rolling out RBAC across the codebase. I had already built it into the front-end and have followed Authentication | RedwoodJS Docs and Role-based Access Control (RBAC) | RedwoodJS Docs

Regarding locking down the back-end, there are guidelines for locking down both Prisma services and GraphQL. Although the two are tightly integrated in the stack, my inclination is that the best approach is to lock down both in case one ends up having a vulnerability. Defense in depth. Layered protection.

My question is regarding the @requireAuth() GraphQL directive Directives | RedwoodJS Docs listed on the bottom of the Authentication | RedwoodJS Docs page (NB: locking down the GraphQL side isn’t mentioned at all on the RBAC page - I would think it should be - that page only references locking down the services).

Is there any way to pass a variable into that directive? It is within gql`` string interpolation, and standard JavaScript interpolation doesn’t work in this instance. I would like to lock my GraphQL API down to only specific roles, but I hate the idea of having to manually edit every single GraphQL schema if I want to change those. It’s not a good use of time, and it’s error-prone.

I have my RBAC roles defined in a separate module that is imported. I have groups like read only, write access, data manager, admin - this way I can easily control which roles have which access. I often know I want to have all “write access” roles able to call a mutation, for example. Makes it much easier to manage. But I can’t for the life of me find how to pass those into the gql`` query string. I don’t want to pass them as variables in the GraphQL call, because somebody could then pass different values and potentially bypass those protections.

Is there any way to include a string variable within the gql`` schema definition so they can be used in the @requireAuth() directive?

I guess the alternative is to roll custom directives (Directives | RedwoodJS Docs) that are group-specific, e.g. @requireWriteAccess(), but wondering if that’s the best way or if there are alternatives.

Could you provide a concrete example of the variable you’d want to pass, the value. Where it comes from and what you want to restrict access to?

It sounds like a custom validator directive is what you need — or maybe several.

Sure - sorry, I should have included that in the initial post.

The role names are defined as follows, in a common module:

const adminRole = 'Admin'
const modifyRole = 'Modify'
const readOnlyRole = 'ReadOnly'

const allRoles = [adminRole, modifyRole, readOnlyRole]
const writeAccessRoles = [adminRole, modifyRole]

These roles are used throughout the code using hasRole() on the front-end side. On the back-end, I can easily include these in my service definitions to lock down the Prisma side. Where I’m having trouble is in GraphQL. Example schema:

export const schema = gql`
  type Procedure {
    id: Int!
    name: String!
  }

  type Query {
    procedures: [Procedure!]! @requireAuth
    procedure(id: Int!): Procedure @requireAuth
  }

  input CreateProcedureInput {
    name: String!
  }


  type Mutation {
    createProcedure(input: CreateProcedureInput!): Procedure! @requireAuth
}
`

I would like to lock down the createProcedure mutation to users with any role in writeAccessRoles. I can do it manually as follows:

  type Mutation {
    createProcedure(input: CreateProcedureInput!): Procedure!
      @requireAuth(roles: ["Modify", "Admin"])
    }
  }

But we have numerous models and various mutations with each, and if we need to add or remove a role to write access in the future, we then have to go into each mutation in each SDL and add or remove the changes. Which, of course, is more error prone. I’d like to just be able to define the higher-level groups, as the arrays above, and use those to grant access.

I’ve tried to create a string representation of the list that gets passed to @requireAuth(roles: ) but if I pass it as such:

const strRoles = '["Modify", "Admin"]'
...
    createProcedure(input: CreateProcedureInput!): Procedure!
      @requireAuth(roles: ${strRoles})

The console says Schema loading failed. Unknown type: "Procedure".

My IDE reports 'createProcedure' uses an illegal value for the argument 'roles' on directive 'requireAuth'. Argument value is not a valid value of scalar 'String

It seems like I can create a validator custom directive Directives | RedwoodJS Docs that either accepts one of my group names, which is probably easiest, or a validator for each group. I don’t anticipate having a lot of RBAC groups, but as we’re rolling the app out to various departments in our company, there are additional use cases that are coming up.

GraphQL tag aka gql in the CodeFile code generator loader doesn’t support string interpolation like that unfortunately.

Your best bet is to set the values manually on each requireAuth or to make several validator directives for requireAnyRole or requireWriteRole etc. and in that specify a collection of roles.