Search code examples
neo4jgraphqlnestjsneo4j-graphql-js

@neo4j/graphql and @auth directive usage for CRUD operations


I'm using @neo4j/graphql library to define my graphql API interface. I've got my Todo model and I would like anyone to read it, but I'd like only admin role to be able to edit it. I'm using NestJS as backend. Type definition is as follows:

// type-defs.ts
export typeDefs = gql(`
type Todo {
    id: ID! @id
    owner: String!
    title: String
  }

  extend type Todo
    @auth(
      rules: [
        { operations: [READ], allowUnauthenticated: true }
        { operations: [CREATE, DELETE, UPDATE], allow: { roles: ["ADMIN"] } }
      ]
    )
`);


// gql.module.ts

const neoSchema = new Neo4jGraphQL({
  typeDefs,
  driver,
  plugins: {
    auth: new Neo4jGraphQLAuthJWKSPlugin({
      jwksEndpoint: `https://cognito-idp.${process.env.COGNITO_REGION}.amazonaws.com/${process.env.COGNITO_USER_POOL_ID}`,
    }),
  },
});

@Module({
  providers: [],
  imports: [
    GraphQLModule.forRootAsync<ApolloDriverConfig>({
      driver: ApolloDriver,
      useFactory: async () => {
        const schema = await neoSchema.getSchema();
        await neoSchema.assertIndexesAndConstraints({
          options: { create: true },
        });
        return {
          playground: true,
          schema,
          // // change property `cognito:groups` to `roles` in the jwt.payload passed to Neo4jGraphQLAuthJWKSPlugin
          context: authContextFunction,
        };
      },
    }),
  ],
})
export class GqlModule {}

I'd expect all users to be able to read it, but only logged in and admins to be able to perform any CUD operation. If I run this without token, I get Unauthenticated error, which is perfect. However, when I use token generated by hand, it allows me to create content. Here is the token passed to the auth plugin:

 {
  sub: '10',
  email: '[email protected]',
  iat: 1562061850,
  exp: 1562065450,
  roles: [ 'B' ]
}


Solution

  • The issue with your Schema is how it used the property allow that should be used to perform a match with a property in a Node, to perform a check using the JWT field roles, then you should use the property roles.

    Using your example:

    type Todo {
      id: ID! @id
      owner: String!
      title: String
    }
    
    extend type Todo @auth(
      rules: [
        { operations: [READ], allowUnauthenticated: true }
        { operations: [CREATE, DELETE, UPDATE], roles: ["ADMIN"] }
      ]
    )