@Auth for multiple layers in a query

Hi

I have a simple schema describing the relationships from a consultancy to a project for a solution I am developing. Effectively a Consultancy has many Engagements which have many Programmes which have many Projects.

Schema as follows:

type Person  {
	userName: String! @id 
  	firstName: String! 
	lastName: String! 
}

type Consultancy{
	id: ID! 
	name: String! 
	engagements: [Engagement] @hasInverse(field:consultancy) 
	users: [Person!] 
}

type Engagement  {
	id: ID! 
	name: String! 
	consultancy: Consultancy! 
	programmes: [Programme] @hasInverse(field:engagement)
  	users: [Person!] 
}

type Programme  {
	id: ID! 
	name: String! 
	engagement: Engagement! 
	projects: [Project] @hasInverse(field:programme)
  	users: [Person!] 
}

type Project  {
	id: ID! 
	name: String! 
	programme: Programme! 
  	users: [Person!] 
}

What I am trying to get my head around is how to restrict access using @Auth (I will have a JWT token with a key ‘email’ which contains… well the email of the ‘Person’ that has been authenticated).

I cannot work out two things from the documentation:

  1. how can I use a filter to filter for items (Consultancy, Engagement, Programme, Project) where their ‘users’ collection includes a Person with the userName that is equal to the JWT email key value.

  2. my queryConsultancy query, by virtue of having a collection of Engagements, allows access to any Engagements that are related to the Consultancy and therefore I need to be able to also restrict access through the queryConsultancy query to those engagements based on the same principle as for the Consultancies. In turn that cascades into the programmes and projects too with the same restrictions being required.

In pseudo code what I need is:

query MyQuery {
  queryConsultancy (where a user has the JWT email value) {
    id
    name
    engagements (where a user has the JWT email value) {
      id
      name
      programmes (where a user has the JWT email value) {
        id
        name
        projects (where a user has the JWT email value) {
          id
          name
        }
      }
    }
  }
}

I am sure this cannot be a novel use case but I am struggling with the docs and my emerging understanding of GraphQL.

Thanks in advance

Just a slight addition to the post - If I am approaching this with a bad design principle to start with please do feel free to point that out with helpful advice on a better approach - that would be appreciated too!

Have I been really dim?..

My head was in a ‘secure an API end-point’ frame of mind i.e. the query needs @auth rules applied but it just clicked that in /Graph @auth rules are applied at the type level not the query level and therefore will inherently be applied to nested arrays of types within a query.

Is that right or have i still missed the @auth model in /graph?

Thanks in advance

Yes, auth rules are applied at type level. You may add different auth rules for adding, deleting, updating and querying a data type.

This is not completely true.
Example:
Consultancy has a query auth rule defined and Engagement does not have any auth rule.
This will only put all objects of type Consultancy behind auth rules. Objects of type Engagement, even if part of some consultancy won’t be behind any auth rules.
This means that querying queryConsultancy with unsatisfied auth rule, no data will be returned. But as Engagement does not have any auth rules, data will be returned while querying queryEngagement.

You may use the auth query rule on type Consultancy as follows:

type Consultancy  @auth(
    query: { rule: """
       query($email: String!){
          queryConsultancy{
             users(filter:{userName:{eq:$email}}){
                userName
             }
          }
       }   
       """
    }
){
	id: ID! 
	name: String! 
	engagements: [Engagement] @hasInverse(field:consultancy) 
	users: [Person!] 
}

The email provided using the JWT token will be used as $email variable in the auth query.
What this auth query does is that, it will filter out only the consultancies for which the users contains provided email as userName.

Can an Engagement, Project, Programme be part of multiple Consultancies with different Users. In that case, you may have to add similar auth query rule to Engagement and other types as well.

If an Engagement is going to be part of a single Consultancy and Engagement is not going to be queried separately with queryEngagement, it will make more sense to not have auth rules for Engagement and use generate directive to explicitly disable queryEngagement query.

In case you are looking for more examples of using @auth, there is Todo App Tutorial repo containing schema and auth examples of a Todo Auth app.

Thanks for your feedback about @auth directive documentation. We will also be looking at improving it. Do let us know if you have any other questions.