<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ian Kleats</title>
    <description>The latest articles on DEV Community by Ian Kleats (@imkleats).</description>
    <link>https://dev.to/imkleats</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F339265%2F5479a415-2847-4363-905c-a9ab831d2e75.jpg</url>
      <title>DEV Community: Ian Kleats</title>
      <link>https://dev.to/imkleats</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imkleats"/>
    <language>en</language>
    <item>
      <title>Easy GraphQL Access Control with GRANDstack</title>
      <dc:creator>Ian Kleats</dc:creator>
      <pubDate>Sun, 06 Sep 2020 17:58:02 +0000</pubDate>
      <link>https://dev.to/imkleats/easy-graphql-access-control-with-grandstack-1l0n</link>
      <guid>https://dev.to/imkleats/easy-graphql-access-control-with-grandstack-1l0n</guid>
      <description>&lt;h3&gt;
  
  
  This article might be for you if you're interested in...
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A quick and flexible development experience to build:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-tenant apps&lt;/li&gt;
&lt;li&gt;Apps that let their users choose:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WHAT&lt;/strong&gt; data they want to share &lt;em&gt;and&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WHO&lt;/strong&gt; to share it with&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Collaboration apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GRANDstack (i.e. GraphQL, React, Apollo, Neo4j Database) already lowers technical overhead for initial app development, but it can be complicated or difficult to implement the above access-control features yourself. I'd like to share a package that fills those gaps, making the GRANDstack one of the best options for getting your next MVP up and running.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long ago in a galaxy far, far away...
&lt;/h3&gt;

&lt;p&gt;Exaggeration is fun, but seriously. A while back, I wrote a &lt;a href="https://dev.to/imkleats/series/5036"&gt;series of articles&lt;/a&gt; exploring some thoughts about GRANDstack (i.e. GraphQL, React, Apollo, Neo4j Database) and how its nested relationship filtering could be applied to access control. It feels like forever ago. Something called 2020 happened, and it took a while for it to go from rough proof-of-concept code to something I could share.&lt;/p&gt;

&lt;p&gt;That day has come.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing: &lt;code&gt;neo4j-deepauth&lt;/code&gt; v0.2.0 release
&lt;/h2&gt;

&lt;p&gt;Directive-based support for fine-grained access control in &lt;code&gt;neo4j-graphql-js&lt;/code&gt; GraphQL endpoints (i.e. GRANDstack apps). Notable improvements from the early thoughts/code I shared include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Restoring baseline &lt;code&gt;filter&lt;/code&gt; functionality.&lt;/li&gt;
&lt;li&gt;Adding support for &lt;code&gt;@deepAuth&lt;/code&gt; to be applied to an Interface and any Object Type that implements it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using the &lt;code&gt;neo4j-deepauth&lt;/code&gt; package
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Install package via NPM or Yarn
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;yarn add neo4j-deepauth&lt;/code&gt; or &lt;code&gt;npm install neo4j-deepauth&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Link to NPM page: &lt;a href="https://www.npmjs.com/package/neo4j-deepauth"&gt;https://www.npmjs.com/package/neo4j-deepauth&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Add schema definition for &lt;code&gt;@deepAuth&lt;/code&gt; directive to your SDL.
&lt;/h4&gt;

&lt;p&gt;Your type definitions should include the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  # Other TypeDefs you defined before

  directive @deepAuth(
    path: String
    variables: [String]
  ) on OBJECT | INTERFACE
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Note that, under its current implementation, the behavior of &lt;code&gt;@deepAuth&lt;/code&gt; will only be applied to Objects or Interface types. A hotfix is in the works for "Relationship Types" due to the way &lt;code&gt;neo4j-graphql-js&lt;/code&gt; generates new Object type definitions  Field-level access control can be implemented (rather inelegantly but simply) by moving restricted fields onto their own Object with a one-to-one relationship to the primary Type.&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Add directive to user-defined types.
&lt;/h4&gt;

&lt;p&gt;Modify your previously-defined type definitions by including &lt;code&gt;@deepAuth&lt;/code&gt; on any Object you want it to apply to. Using our To-Do example, that might look like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`

type User @deepAuth(
  path: """{ OR: [{userId: "$user_id"},
                {friends_some: {userId: "$user_id"}}] }""",
  variables: ["$user_id"]
){
  userId: ID!
  firstName: String
  lastName: String
  email: String!
  friends: [User] @relation(name: "FRIENDS_WITH", direction: "OUT")
  taskList: [Task] @relation(name: "TO_DO", direction: "OUT")
  visibleTasks: [Task] @relation(name: "CAN_READ", direction: "IN")
}

type Task @deepAuth(
  path: """{ visibleTo_some: {userId: "$user_id"} }"""
  variables: ["$user_id"]
) {
  taskId: ID!
  name: String!
  details: String
  location: Point
  complete: Boolean!
  assignedTo: User @relation(name: "TO_DO", direction: "IN")
  visibleTo: [User] @relation(name: "CAN_READ", direction: "OUT")
}

# ...Directive definition from above
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here we've limited access to Users if: a) the client is the &lt;code&gt;User&lt;/code&gt;; or b) the client is friends with the &lt;code&gt;User&lt;/code&gt;. And we've limited access to &lt;code&gt;Tasks&lt;/code&gt; if and only if the client's &lt;code&gt;User&lt;/code&gt; has a &lt;code&gt;CAN_READ&lt;/code&gt; relationship to the &lt;code&gt;Task&lt;/code&gt;. &lt;strong&gt;This is not the only or best authorization structure, just a simple example.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Please note that the &lt;code&gt;path&lt;/code&gt; argument strongly corresponds to the filter argument Input Types that would define the existence of the ACL structure. Declaring a &lt;code&gt;path&lt;/code&gt; argument that does not conform to the correct filter Input Type is a potential cause of errors when &lt;code&gt;applyDeepAuth&lt;/code&gt; attempts to coerce the argument value to that type.&lt;/p&gt;
&lt;h4&gt;
  
  
  4. Modify resolvers and request context
&lt;/h4&gt;

&lt;p&gt;Unless or until &lt;code&gt;@deepAuth&lt;/code&gt; is integrated as a broader feature into &lt;code&gt;neo4j-graphql-js&lt;/code&gt;, we will not be able to rely on the automatically-generated resolvers. We will have to modify them ourselves.&lt;/p&gt;

&lt;p&gt;Per the &lt;a href="https://grandstack.io/docs/neo4j-graphql-js.html#translate-graphql-to-cypher"&gt;GRANDstack docs&lt;/a&gt;, "inside each resolver, use neo4j-graphql() to generate the Cypher required to resolve the GraphQL query, passing through the query arguments, context and resolveInfo objects." This would normally look like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;neo4j-graphql-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolvers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// entry point to GraphQL service&lt;/span&gt;
  &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As alluded to above, we must modify these resolvers to replace the &lt;code&gt;resolveInfo.operation&lt;/code&gt; and &lt;code&gt;resolveInfo.fragments&lt;/code&gt; used by &lt;code&gt;neo4jgraphql()&lt;/code&gt; with the pieces of your transformed query. Additionally, it should be noted that the top-level filter is obtained by &lt;code&gt;neo4jgraphql()&lt;/code&gt; from the &lt;code&gt;params&lt;/code&gt; argument, while subsequent filters are obtained from the &lt;code&gt;resolveInfo&lt;/code&gt;. That might look something like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;neo4j-graphql-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;applyDeepAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;neo4j-deepauth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolvers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// entry point to GraphQL service&lt;/span&gt;
  &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;authParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authResolveInfo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;applyDeepAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authResolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;authParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authResolveInfo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;applyDeepAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authResolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you use any &lt;code&gt;variables&lt;/code&gt; in your &lt;code&gt;@deepAuth&lt;/code&gt; directives, you must define them within your request context with the key as it appears in your &lt;code&gt;variables&lt;/code&gt; argument. Here is an example of how to add values to the &lt;code&gt;deepAuthParams&lt;/code&gt; in the context using &lt;code&gt;express-graphql&lt;/code&gt; (&lt;em&gt;Note: issues with ApolloServer have been diagnosed and resolved in the v0.2.1 release, but we can still give express-graphql some love.&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;graphqlHTTP&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;deepAuthParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;})));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  5. Update Custom Mutations
&lt;/h4&gt;

&lt;p&gt;The automatically-generated mutations will not currently respect or enforce the authorization paths provided on &lt;code&gt;@deepAuth&lt;/code&gt;. Also, it will often be helpful or necessary to create/delete additional authorization nodes/relationships in the same transaction as a &lt;code&gt;Create&lt;/code&gt;/&lt;code&gt;Delete&lt;/code&gt; mutation.&lt;/p&gt;

&lt;p&gt;For these reasons, you will need to create your own custom mutation resolvers for pretty much any Type that has &lt;code&gt;@deepAuth&lt;/code&gt; applied or has a relationship to a &lt;code&gt;@deepAuth&lt;/code&gt;ed Type.&lt;/p&gt;
&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;An example of &lt;code&gt;neo4j-deepauth&lt;/code&gt; use can be found at &lt;a href="https://github.com/imkleats/neo4j-deepauth-example"&gt;github.com/imkleats/neo4j-deepauth-example&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/imkleats"&gt;
        imkleats
      &lt;/a&gt; / &lt;a href="https://github.com/imkleats/neo4j-deepauth-example"&gt;
        neo4j-deepauth-example
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      ApolloServer example with neo4j-graphql-js and neo4j-deepauth
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Issues and Contributions
&lt;/h2&gt;

&lt;p&gt;As an early version number release, I'm still working on identifying all edge cases and continually fleshing out the test suite.  If you run into any bugs or have ideas for future feature releases, please open up an Issue on the Github repository.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/imkleats"&gt;
        imkleats
      &lt;/a&gt; / &lt;a href="https://github.com/imkleats/neo4j-graphql-deepauth"&gt;
        neo4j-graphql-deepauth
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Directive-based support for fine-grained access control in neo4j-graphql-js GraphQL endpoints
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Thanks for listening! Hope you find it useful, and I look forward to hearing from you!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>apollo</category>
      <category>react</category>
      <category>neo4j</category>
    </item>
    <item>
      <title>GRANDstack Access Control - Checking out the MVP</title>
      <dc:creator>Ian Kleats</dc:creator>
      <pubDate>Tue, 10 Mar 2020 01:23:59 +0000</pubDate>
      <link>https://dev.to/imkleats/grandstack-access-control-checking-out-the-mvp-35o7</link>
      <guid>https://dev.to/imkleats/grandstack-access-control-checking-out-the-mvp-35o7</guid>
      <description>&lt;p&gt;Hi! It's me again. Welcome to this fifth article in my series on discretionary access control with the &lt;a href="https://grandstack.io"&gt;GRANDstack&lt;/a&gt;. The past couple posts have ventured into some highly theoretical territory. After "losing" a weekend for some snowboarding (aka shredding the gnar), I have finally caught my code up to &lt;em&gt;actually do&lt;/em&gt; all the things I &lt;em&gt;talked&lt;/em&gt; about doing. I don't know about you, but I am super duper excited.&lt;/p&gt;

&lt;p&gt;This article will cover the features implemented currently, lay out limitations that I intend to address with later enhancements (i.e. future articles), and demonstrate how this tool might be integrated into a &lt;code&gt;neo4j-graphql-js&lt;/code&gt;-generated endpoint. First things first, let me show you the code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/imkleats"&gt;
        imkleats
      &lt;/a&gt; / &lt;a href="https://github.com/imkleats/neo4j-graphql-deepauth"&gt;
        neo4j-graphql-deepauth
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Directive-based support for fine-grained access control in neo4j-graphql-js GraphQL endpoints
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h4&gt;
  
  
  Disclaimer and Reminder
&lt;/h4&gt;

&lt;p&gt;The importance of data privacy cannot be overstated. Aside from any legal obligations, we have a moral responsibility as coders/developers to ensure the safety of those using our products. It is not hyperbole to say that poorly constructed access control can literally put people's lives at risk.&lt;/p&gt;

&lt;p&gt;At this stage, please do not assume my work is production-ready. I make no guarantees of its quality or potential flaws. If you want to use this code, be responsible in writing your own unit and integration tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  @deepAuth MVP build
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Minimum Viable Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Anyone building a GraphQL backend using &lt;code&gt;neo4j-graphql-js&lt;/code&gt; should be able to add fine-grained access control to their read-resources in three easy steps.

&lt;ol&gt;
&lt;li&gt;Add schema definition for &lt;code&gt;@deepAuth&lt;/code&gt; directive to your SDL.&lt;/li&gt;
&lt;li&gt;Add directive to user-defined types.&lt;/li&gt;
&lt;li&gt;Modify resolvers to replace the &lt;code&gt;resolveInfo.operation&lt;/code&gt; and &lt;code&gt;resolveInfo.fragments&lt;/code&gt; used by &lt;code&gt;neo4jgraphql()&lt;/code&gt; with the pieces of your transformed query.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Powerful Security&lt;/strong&gt;: Clients should be able to access only the information for which they have been granted permission.

&lt;ul&gt;
&lt;li&gt;Leverage Neo4j's graph database capabilities to efficiently traverse arbitrarily complex access control relationships.&lt;/li&gt;
&lt;li&gt;Prevents inference of unauthorized nested data by removing any client-defined filter arguments prior to execution. (Future enhancement to allow and dynamically modify client-defined filter arguments.)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility &amp;amp; Freedom&lt;/strong&gt;: In designing &lt;code&gt;@deepAuth&lt;/code&gt;, a heavy premium was placed on &lt;em&gt;&lt;strong&gt;extensibility&lt;/strong&gt;&lt;/em&gt;.

&lt;ul&gt;
&lt;li&gt;Strive for great access control functionality out-of-the-box, but recognize that others might have different needs or ideas about what works for them.&lt;/li&gt;
&lt;li&gt;Users are free to extend or modify the default behavior of &lt;code&gt;@deepAuth&lt;/code&gt; by creating their own TranslationRules.&lt;/li&gt;
&lt;li&gt;This TranslationRule pattern/approach is also not limited to directives. Get creative with it!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Enhancement Roadmap&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;del&gt;Object-level &lt;code&gt;@deepAuth&lt;/code&gt; directive support.&lt;/del&gt; Complete&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;Remove client-defined &lt;code&gt;filter&lt;/code&gt; arguments on GraphQL queries&lt;/del&gt; Complete&lt;/li&gt;
&lt;li&gt;Field-level &lt;code&gt;@deepAuth&lt;/code&gt; directive support.

&lt;ul&gt;
&lt;li&gt;Path argument will define path to a fieldPermissions node.&lt;/li&gt;
&lt;li&gt;TranslationRule will add this fieldPermissions node to selectionSet.&lt;/li&gt;
&lt;li&gt;Apollo tooling will be used to validate field-level permissions based on this extra data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Nested filter support.

&lt;ul&gt;
&lt;li&gt;Restore client ability to supply filter arguments.&lt;/li&gt;
&lt;li&gt;Use additional TranslationRule visitors to traverse existing filter arguments.&lt;/li&gt;
&lt;li&gt;Wrap components of the existing filter argument with applicable &lt;code&gt;@deepAuth&lt;/code&gt; filter.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Mutation support.

&lt;ul&gt;
&lt;li&gt;Attach newly-created nodes to a defined access control structure.&lt;/li&gt;
&lt;li&gt;Use an &lt;code&gt;OperationDefinition&lt;/code&gt; visitor in the TranslationRule to generate additional dependent mutations.&lt;/li&gt;
&lt;li&gt;Submit all dependent mutations as a single database transaction.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Demonstration of Intended Flow&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Add schema definition for &lt;code&gt;@deepAuth&lt;/code&gt; directive to your SDL.
&lt;/h4&gt;

&lt;p&gt;Your type definitions should include the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  # Other TypeDefs you defined before

  directive @deepAuth(
    path: String
    variables: [String]
  ) on OBJECT
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that, under its current implementation, the behavior of &lt;code&gt;@deepAuth&lt;/code&gt; will only be applied to Objects. Field-level access control will be the next topic I cover and implement. For forward-compatibility, you can safely use &lt;code&gt;on OBJECT | FIELD_DEFINITION&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Add directive to user-defined types.
&lt;/h4&gt;

&lt;p&gt;Modify your previously-defined type definitions by including &lt;code&gt;@deepAuth&lt;/code&gt; on any Object you want it to apply to. Using our To-Do example, that might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`

type User @deepAuth(
  path: """OR: [{userId: "$user_id"},
                {friends_some: {userId: "$user_id"}}]""",
  variables: ["$user_id"]
){
  userId: ID!
  firstName: String
  lastName: String
  email: String!
  friends: [User] @relation(name: "FRIENDS_WITH", direction: "OUT")
  taskList: [Task] @relation(name: "TO_DO", direction: "OUT")
  visibleTasks: [Task] @relation(name: "CAN_READ", direction: "IN")
}

type Task @deepAuth(
  path: """visibleTo_some: {userId: "$user_id"}"""
  variables: ["$user_id"]
) {
  taskId: ID!
  name: String!
  details: String
  location: Point
  complete: Boolean!
  assignedTo: User @relation(name: "TO_DO", direction: "IN")
  visibleTo: [User] @relation(name: "CAN_READ", direction: "OUT")
}

# ...Directive definition from above
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we've limited access to Users if: a) the client is the &lt;code&gt;User&lt;/code&gt;; or b) the client is friends with the &lt;code&gt;User&lt;/code&gt;. And we've limited access to &lt;code&gt;Tasks&lt;/code&gt; if and only if the client's &lt;code&gt;User&lt;/code&gt; has a &lt;code&gt;CAN_READ&lt;/code&gt; relationship to the &lt;code&gt;Task&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Please note that, while the &lt;code&gt;path&lt;/code&gt; argument generally corresponds to the filter argument that would define the existence of the ACL structure, it must be written without being enclosed by brackets at the outermost level (i.e. just &lt;code&gt;path&lt;/code&gt; not &lt;code&gt;{ path }&lt;/code&gt;). &lt;/p&gt;

&lt;h4&gt;
  
  
  3. Modify resolvers and request context
&lt;/h4&gt;

&lt;p&gt;Unfortunately, unless or until &lt;code&gt;@deepAuth&lt;/code&gt; is integrated as a broader feature into &lt;code&gt;neo4j-graphql-js&lt;/code&gt;, we will not be able to rely on the automatically-generated resolvers. We will have to modify them ourselves.&lt;/p&gt;

&lt;p&gt;Per the &lt;a href="https://grandstack.io/docs/neo4j-graphql-js.html#translate-graphql-to-cypher"&gt;GRANDstack docs&lt;/a&gt;, "inside each resolver, use neo4j-graphql() to generate the Cypher required to resolve the GraphQL query, passing through the query arguments, context and resolveInfo objects." This would normally look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;neo4j-graphql-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolvers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// entry point to GraphQL service&lt;/span&gt;
  &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As alluded to above, we must modify these resolvers to replace the &lt;code&gt;resolveInfo.operation&lt;/code&gt; and &lt;code&gt;resolveInfo.fragments&lt;/code&gt; used by &lt;code&gt;neo4jgraphql()&lt;/code&gt; with the pieces of your transformed query. That might look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;neo4j-graphql-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;applyDeepAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../neo4j-graphql-deepauth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolvers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// entry point to GraphQL service&lt;/span&gt;
  &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authResolveInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;applyDeepAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authResolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authResolveInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;applyDeepAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;neo4jgraphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authResolveInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use any &lt;code&gt;variables&lt;/code&gt; in your &lt;code&gt;@deepAuth&lt;/code&gt; directives, you must define them within your request context with the key as it appears in your &lt;code&gt;variables&lt;/code&gt; argument. Here is an example of how to add values to the &lt;code&gt;deepAuthParams&lt;/code&gt; in the context using ApolloServer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;deepAuthParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Where do we go from here?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Hmmm, good question. I still need to build a lot of tests for the code I've written. Of the three items on my "Enhancement Roadmap", getting nested filter functionality restored is probably the most important, but it's also the most technically challenging.&lt;/p&gt;

&lt;p&gt;Field-level access control is probably the easiest, and mutations are fairly straightforward but to introduce database transactions requires re-implementing some parts of &lt;code&gt;neo4jgraphql()&lt;/code&gt;. So who knows. I'm leaning towards field-level access control so I can focus on tests.&lt;/p&gt;

&lt;p&gt;Thanks for joining me on my journey. We're in a pretty good spot, but there's a fair distance we have yet to travel. Till next time!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>grandstack</category>
      <category>neo4j</category>
      <category>node</category>
    </item>
    <item>
      <title>GRANDstack Access Control - Generating the Filter Argument</title>
      <dc:creator>Ian Kleats</dc:creator>
      <pubDate>Thu, 27 Feb 2020 19:17:44 +0000</pubDate>
      <link>https://dev.to/imkleats/grandstack-access-control-generating-the-filter-argument-2dnc</link>
      <guid>https://dev.to/imkleats/grandstack-access-control-generating-the-filter-argument-2dnc</guid>
      <description>&lt;p&gt;Hi there. This is the fourth stop on my journey to implement discretionary access control for &lt;a href="https://grandstack.io"&gt;GRANDstack&lt;/a&gt; applications. Today, we are going to embark on a mission to generate the filter arguments we need for to modify our GraphQL request ASTs.&lt;/p&gt;

&lt;p&gt;If you're joining me for the first time, welcome and thank you! I strongly encourage you to check out the previous articles in this series.&lt;/p&gt;

&lt;h4&gt;
  
  
  Last time on "As the Graph Turns"...
&lt;/h4&gt;

&lt;p&gt;We started jumping right into applying the pattern I introduced in the second article for GraphQL AST translation/transformation (here's a link to the repo that &lt;a href="https://github.com/imkleats/graphql-ast-tools"&gt;lays this out&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We defined the &lt;code&gt;@deepAuth&lt;/code&gt; directive on our schema.&lt;/li&gt;
&lt;li&gt;We envisioned the structure of our post-traversal &lt;code&gt;AstMap&lt;/code&gt;, which allowed us to define an &lt;code&gt;AstCoalescer&lt;/code&gt; function to string our final, modified GraphQL request AST together.&lt;/li&gt;
&lt;li&gt;We also established a skeleton of the &lt;code&gt;TranslationRule&lt;/code&gt; that would lead to our idealized &lt;code&gt;AstMap&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I mentioned then, I'm outpacing the code I've developed. The bright side? We get to spend time digging a little more deeply into the actual implementation of the &lt;code&gt;TranslationRule&lt;/code&gt;. Let's remind ourselves of that skeleton:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Definition of our Rule to add an authorization filter.&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;AuthorizationFilterRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt;   &lt;span class="c1"&gt;// The TranslationContext class we instantiate in translate().&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Returns an ASTVisitor&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ancestors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ToDoList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"""&lt;/span&gt;&lt;span class="s2"&gt;
         1a) Check for directive on field's type in schema.
         1b) Check for filter arguments on Field node.
         2a) Modify or remove existing filter arguments.
         2b) If 1a is true, wrap 2a with the ACL filter.
         3)  Discern appropriate path for new/modified filter arguments.
         4a) Get current authFilters list from AstMap using `context`.
         4b) Append object with {path: results_of_3, node: results_of_2}
             to 4a (with a higher order function or something similar).
         4c) Post result of 4b to AstMap using `context`.
      &lt;/span&gt;&lt;span class="dl"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// The @return value of visitor functions elicit special behavior.&lt;/span&gt;
      &lt;span class="c1"&gt;// In most cases, we just want to return undefined.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our goal for this leg of the journey is to work on step &lt;strong&gt;(2b)&lt;/strong&gt; from the list above. We are going to lay the foundation for making the ACL filter referenced there.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Going back, way back&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We should probably circle back to something we talked about in the first article. Our goal was to dynamically add filter arguments to our GraphQL queries so that they looked more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query aclTasks($user_id: ID!){
  Task(filter: {visibleTo_some: {userId: $user_id}}) {
    ...task fields
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First of all, I need to say something: I &lt;strong&gt;hate&lt;/strong&gt; that first part. If I were to stick true to that, I would need to open up my &lt;code&gt;TranslationRule&lt;/code&gt; to visit those variable definitions and modify them. It sounds like more work than I should need to do, and I'm lazy.&lt;/p&gt;

&lt;p&gt;But more importantly... where will this access control list path come from? And how do we handle the dynamic parts (i.e. user/group identifiers) if we aren't using query variables? We need some way for our backend developer to tell us that &lt;code&gt;{visibleTo_some: {userId: $user_id}}&lt;/code&gt; is the right access control filter to apply to the Task object type and which part of that path is a variable.&lt;/p&gt;

&lt;p&gt;Here's what I am going to propose. We require the user to provide the following arguments and data types for those arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deepAuthArgsForTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;aclPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{visibleTo_some: {userId: $user_id}}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// String&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$user_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// Array of String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we have this payload of arguments (still being agnostic about &lt;em&gt;how&lt;/em&gt; we get them), we can do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MetaCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"""&lt;/span&gt;&lt;span class="s2"&gt;
  1) Pull the value of variable arguments from some available options/context.
      -- This can be accessible from our TranslationContext.

  2) Use regex to replace instances of the variable arguments in the aclPath
     string with the values obtained in Step 1.

  3) Use a string literal of a very simple GraphQL query to put the string
     generated by Step 2 into a filter argument.

  4) Use the `parse` function from graphql-js to parse that string into a
     Document AST.

  5) Returned the filter Argument node value from the parsed AST for our uses.
&lt;/span&gt;&lt;span class="dl"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Now where do we get those arguments?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We've laid out the arguments we need and how those arguments will be used, but we've been agnostic as to how we are going to deliver those arguments. There might be more choices, but two of the most obvious are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Attaching them to the same available options/context that we would be using in &lt;strong&gt;Step 1&lt;/strong&gt; of the meta-code I've written above.

&lt;ul&gt;
&lt;li&gt;This might have some benefit in that it obfuscates the access control structure from your GraphQL schema.&lt;/li&gt;
&lt;li&gt;One possible downside is that we've continued to remain agnostic as to whether this query document transformation will occur as middleware prior to hitting the GraphQL server or within our root resolver functions. I don't know how that might complicate things.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Adding these as directive arguments in our GraphQL schema.

&lt;ul&gt;
&lt;li&gt;Basically the opposite pros-cons from the previous choice.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't really an either-or choice. We can implement both, I think, as long as we are mindful of precedence when we get both. Since the process of adding an options object to a request context is fairly well documented, I will focus solely on the directive arguments. We need to revise our directive definition in our type definitions to be more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  # Other TypeDefs you defined before...

  directive @deepAuth(
    aclPath: String
    variables: [String]
  ) on OBJECT | FIELD_DEFINITION
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Wrapping up&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Thanks for joining me in my digital white-boarding exercise. It was a little shorter than our last few adventures together, but I think we've made progress nonetheless, don't you? We can continue our efforts to implement the &lt;code&gt;AuthorizationFilterRule&lt;/code&gt; with our heads held high.&lt;/p&gt;

&lt;p&gt;As always, as you continue to digest this material, if you have any questions / comments / contributions, please do share them. Till next time!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>grandstack</category>
      <category>neo4j</category>
      <category>node</category>
    </item>
    <item>
      <title>GRANDstack Access Control - Query Translation Strategy</title>
      <dc:creator>Ian Kleats</dc:creator>
      <pubDate>Thu, 27 Feb 2020 02:09:11 +0000</pubDate>
      <link>https://dev.to/imkleats/grandstack-access-control-query-translation-strategy-1k1f</link>
      <guid>https://dev.to/imkleats/grandstack-access-control-query-translation-strategy-1k1f</guid>
      <description>&lt;p&gt;Howdy! Welcome back to Part 3 of my series on discretionary access control in the &lt;a href="https://grandstack.io" rel="noopener noreferrer"&gt;GRANDstack&lt;/a&gt;. If you're still with me after that last article, &lt;em&gt;mil gracias&lt;/em&gt;. As promised, we are going to define and empower a schema directive to lock down our assets.&lt;/p&gt;

&lt;h4&gt;
  
  
  Recapping our journey so far...
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;We motivated our work by thinking about a GRANDstack To-do app.

&lt;ul&gt;
&lt;li&gt;Our first to-do? Keep Bob from down the street out of our  to-do list.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;We identified that the powerful nested/relational filtering from &lt;code&gt;neo4j-graphql-js&lt;/code&gt; could be used to restrict our query results based on some arbitrary access control structure.

&lt;ul&gt;
&lt;li&gt;Our second to-do? Automate that filter behavior using a schema directive.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Then, we needed to explore how GraphQL processes an operation (i.e. query or mutation) from request through result to understand potential implementations.&lt;/li&gt;

&lt;li&gt;We learned that the JavaScript reference implementation's &lt;code&gt;graphql/language&lt;/code&gt; module and its &lt;code&gt;validate&lt;/code&gt; function contain utilities and patterns that "fit" the query transformation problem we're trying to solve.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Today, we'll apply the pattern we described by writing a &lt;code&gt;TranslationRule&lt;/code&gt; to add a filter argument to our Document ASTs for every type/field that we put this new directive on within our type definitions.&lt;/p&gt;

&lt;p&gt;This endeavor will assume you're familiar with (or can reference on the fly) the repository I shared last time that lays out the pattern we'll be using:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/imkleats" rel="noopener noreferrer"&gt;
        imkleats
      &lt;/a&gt; / &lt;a href="https://github.com/imkleats/graphql-ast-tools" rel="noopener noreferrer"&gt;
        graphql-ast-tools
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Rule-based translation of GraphQL Document ASTs to ASTs of other query languages
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h4&gt;
  
  
  Full disclosure:
&lt;/h4&gt;

&lt;p&gt;I'm developing best practices as I write this, so feel free to offer different opinions in the comments or as issues in the above repo.&lt;/p&gt;

&lt;p&gt;The other thing is that this is a hobby for me. My biggest well of time to work on this is the weekend... only after devoting time to family and household obligations. In the sake of keeping up the cadence of this series, though, I'm going to be out-pacing some of the code I've already written.&lt;/p&gt;

&lt;p&gt;Some code samples might reference utility functions that I haven't created yet, others might be more like meta programming. If you see where I'm coming from / going to and want to fill in the blanks yourself, I welcome it. Just don't expect my code blocks to be copy-pastable and working.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where do we start?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In thinking through how to approach transformations, let's remind ourselves of the steps involved in the pattern we are going to apply:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receive an incoming GraphQL request, &lt;code&gt;parse&lt;/code&gt; it into an AST, and feed it into &lt;code&gt;translate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;translate&lt;/code&gt; traverses the AST and applies a set of visitor functions that are supplied as &lt;code&gt;TranslationRules&lt;/code&gt; to each AST node it visits.&lt;/li&gt;
&lt;li&gt;These visitor functions, subject to whatever logic you define, emit information that is stored at a specified location in an &lt;code&gt;AstMap&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;This information may include references to pending values in other locations in the &lt;code&gt;AstMap&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Upon traversal completion, a function is invoked to build a new AST (not necessarily a GraphQL AST) from the components of the &lt;code&gt;AstMap&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I am going to propose that we should start with thinking about the state that needs to exist at the end of Step 3 before heading into Step 4.&lt;/p&gt;

&lt;p&gt;In this exercise, we are going to be transforming one GraphQL query into another GraphQL query. Let's think about what that means for the structure of our finalized &lt;code&gt;AstMap&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Scoping our AstMap and Final Coalescer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The first thing that comes to mind as I think about a GraphQL-to-GraphQL transformation is that we could "clone" an entire Document AST with our &lt;code&gt;AstMap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Did I mention I'm lazy, though? Did I? To misquote one of my favorite mercantilist philosophers, C.J. Sparrow:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can always trust a lazy person to conduct your business with the utmost efficiency. Honestly. It's the industrious ones you want to watch out for.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(&lt;em&gt;Isn't there inherent value in knowing how to replicate the full-fledged structure of a GraphQL AST?!?&lt;/em&gt; Of course there is! But meh...)&lt;/p&gt;

&lt;p&gt;To save myself some work, I'm going to ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What parts of the AST are we interested in changing?

&lt;ul&gt;
&lt;li&gt;Argument nodes with Field node parents.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Do we need to care about any of the child nodes of those Argument nodes?

&lt;ul&gt;
&lt;li&gt;The Name and Value nodes tell us if there is an existing "filter" argument.&lt;/li&gt;
&lt;li&gt;None of those children will hold a subsequent Field Node, so we can kind of treat the entire Argument Node as a leaf.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Ok, why did I ask those questions? It's because I wanted to save myself some work, silly. It sounds like we can get away only needing a list of objects that contain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A new or modified Argument Node for our ACL filter; and&lt;/li&gt;
&lt;li&gt;The location in the Document/Operation AST in which to insert that node.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our final AstMap (that is generated by our visitor functions, so not actually a piece of code we have to define) might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AstMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;originalQuery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;original_document_ast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;authFilters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;path_to_filter_arg_1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;new_Argument_Node_1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;path_to_filter_arg_2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;new_Argument_Node_2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;...&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;path_to_filter_arg_N&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;new_Argument_Node_N&lt;/span&gt;&lt;span class="p"&gt;}];&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This could naturally lead to a final &lt;code&gt;AstCoalescer&lt;/code&gt; function (which we do have to define for ourselves) that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash/set&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;finalCoalescer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;astmap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestAst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;astmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;originalQuery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;astmap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;originalQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authFilters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;astmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authFilters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;astmap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authFilters&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="nx"&gt;authFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;authFilter&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestAst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authFilter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authFilter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;requestAst&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Writing a TranslationRule to make that happen&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Mmkay, we know what we want at the end. Now we need to think about which visitor function or set of visitor functions will be necessary to create that structure. &lt;/p&gt;

&lt;h4&gt;
  
  
  Populating originalQuery
&lt;/h4&gt;

&lt;p&gt;If we were going to use a visitor function to produce a copy of the original Document AST, it might make sense to do that at the first node we enter.&lt;/p&gt;

&lt;p&gt;Can we stop to ask ourselves why we would do this through a visitor function?&lt;/p&gt;

&lt;p&gt;Honestly, having the capacity to produce an original version of our AST is probably going to be needed fairly frequently for other applications. Maybe we should just revise &lt;code&gt;translate&lt;/code&gt; to populate this into our &lt;code&gt;AstMap&lt;/code&gt; under a reserved key before any visitation.&lt;/p&gt;

&lt;h4&gt;
  
  
  Populating authFilters
&lt;/h4&gt;

&lt;p&gt;If the &lt;code&gt;originalQuery&lt;/code&gt; is taken care of without any &lt;code&gt;TranslationRule&lt;/code&gt;, our primary concern is now limited to &lt;code&gt;authFilters&lt;/code&gt;. Here's a part -- like I mentioned above -- that I am getting a little ahead of my actual codebase. This next part will be a little more conceptual, and I'll spend more time in the next article to complete the implementation.&lt;/p&gt;

&lt;p&gt;Ok, let's take a second to think: Each visitor function could apply to a specific &lt;code&gt;Kind&lt;/code&gt; of node. What kind of node(s) are we interested in?&lt;/p&gt;

&lt;p&gt;(&lt;em&gt;Duh, we want to modify &lt;code&gt;Argument&lt;/code&gt; nodes in the final AST, so we should write an &lt;code&gt;Argument&lt;/code&gt; visitor!&lt;/em&gt; ...and that is why I am writing this article and not you. Just kidding... mostly. ;p )&lt;/p&gt;

&lt;p&gt;Back to reality. Why would we not use an &lt;code&gt;Argument&lt;/code&gt; visitor? Because there are some &lt;code&gt;Fields&lt;/code&gt; that we will visit which will not currently have any &lt;code&gt;Argument&lt;/code&gt; nodes but will need the schema directive applied to them. Uh-oh, visitors can't visit a node that is undefined.&lt;/p&gt;

&lt;p&gt;However, nothing prevents us from accessing the &lt;code&gt;Argument&lt;/code&gt; node array when stopping at the &lt;code&gt;Field&lt;/code&gt;. We want to do our work when visiting each &lt;code&gt;Field&lt;/code&gt; node.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Are there any other node &lt;code&gt;Kinds&lt;/code&gt; we need to visit?&lt;/em&gt; Nope.&lt;/p&gt;

&lt;p&gt;So, let's put some bones in our &lt;code&gt;Field&lt;/code&gt; visitor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Definition of our Rule to add an authorization filter.&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;AuthorizationFilterRule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt;   &lt;span class="c1"&gt;// The TranslationContext class we instantiate in translate().&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Returns an ASTVisitor&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ancestors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ToDoList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"""&lt;/span&gt;&lt;span class="s2"&gt;
         1a) Check for directive on field's type in schema.
         1b) Check for filter arguments on Field node.
         2a) Modify or remove existing filter arguments.
         2b) If 1a is true, wrap 2a with the ACL filter.
         3)  Discern appropriate path for new/modified filter arguments.
         4a) Get current authFilters list from AstMap using `context`.
         4b) Append object with {path: results_of_3, node: results_of_2}
             to 4a (with a higher order function or something similar).
         4c) Post result of 4b to AstMap using `context`.
      &lt;/span&gt;&lt;span class="dl"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// The @return value of visitor functions elicits special behavior.&lt;/span&gt;
      &lt;span class="c1"&gt;// In most cases, we just want to return undefined.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Adding the Directive to our Schema&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Alright, we kinda sorta have a skeleton for how we are going to implement our &lt;code&gt;AuthorizationFilterRule&lt;/code&gt;. That was a doozy. Take a breath. We've got some momentously difficult work ahead of us ("srs bzns" if you're into the whole brevity thing).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  # Other TypeDefs you defined before
  directive @deepAuth on OBJECT | FIELD_DEFINITION
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. That was it. Seriously. We might think about arguments for that directive, or we might not. I haven't decided yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Wrapping Up&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;That's a wrap on this installment of the series. I wish I could say I wasn't a little bummed out. I really wanted to have an MVP &lt;code&gt;AuthorizationFilterRule&lt;/code&gt; to share with you, and I fell short.&lt;/p&gt;

&lt;p&gt;But hey! We &lt;em&gt;did&lt;/em&gt; cover a lot anyway! Let's choose to be happy. It's probably all for the best in any case since we'll be able to take a deeper dive into those implementation details in the next post. Till next time!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>grandstack</category>
      <category>neo4j</category>
      <category>backend</category>
    </item>
    <item>
      <title>GRANDstack Access Control - Query Transformations</title>
      <dc:creator>Ian Kleats</dc:creator>
      <pubDate>Sun, 23 Feb 2020 21:47:38 +0000</pubDate>
      <link>https://dev.to/imkleats/grandstack-access-control-query-transformations-3po4</link>
      <guid>https://dev.to/imkleats/grandstack-access-control-query-transformations-3po4</guid>
      <description>&lt;p&gt;Welcome back to this exploratory series on discretionary access control with the &lt;a href="https://grandstack.io"&gt;GRANDstack&lt;/a&gt;! First off, I need to fess up about something.&lt;/p&gt;

&lt;p&gt;I lied to you in the last article. I told you we were going to jump right into crafting a schema directive. We are not. That's because I didn't want to have lied again.&lt;/p&gt;

&lt;p&gt;I told you this series would assume "some basic familiarity with GraphQL concepts." We are actually going to be digging into certain parts of the GraphQL reference implementation that you might never see even if you were highly proficient in developing GraphQL backends.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hold up. Can't you just use some &lt;a href="https://www.apollographql.com/"&gt;Apollo&lt;/a&gt; tooling to do a query document &lt;a href="https://www.apollographql.com/docs/apollo-server/api/graphql-tools/#transform"&gt;transformation&lt;/a&gt; and skip this?&lt;/em&gt; Probably for this use-case, but I'm not going to take that route.&lt;/p&gt;

&lt;p&gt;It's selfish, really. I have a pattern for document transformations that I want to riff on because I believe it will elegantly solve some problems when we move on to mutations. I don't want to throw this pattern at you without giving you some background knowledge, though.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where do we start?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let's start at the beginning. Take a look at the GraphQL JavaScript reference implementation's &lt;a href="https://graphql.org/graphql-js/"&gt;Getting Started&lt;/a&gt; section. Notice how the  "Hello World" response is generated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Run the GraphQL query '{ hello }' and print out the response&lt;/span&gt;
&lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{ hello }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ok, so we can see that there is an argument for 'schema' and 'root'. With GRANDstack, both of these are taken care of by &lt;code&gt;makeAugmentedSchema&lt;/code&gt; from &lt;code&gt;neo4j-graphql-js&lt;/code&gt;, so let's ignore 'em for now and maybe later too.&lt;/p&gt;

&lt;p&gt;The middle argument is a query string. Our end goal is to stifle to machinations of your nosy neighbor nemesis, Bob. We talked about how he could circumvent the filter arguments by submitting his own queries that didn't include them. Let's see where that rabbit hole leads.&lt;/p&gt;

&lt;p&gt;If we click on the API &lt;a href="https://graphql.org/graphql-js/graphql/#graphql"&gt;reference link&lt;/a&gt; for the &lt;code&gt;graphql&lt;/code&gt; function, we'd find this description:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h5&gt;
  
  
  graphql
&lt;/h5&gt;


&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GraphQLSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;requestString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;rootValue&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;contextValue&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;variableValues&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;?{[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;operationName&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;GraphQLResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;graphql&lt;/code&gt; function &lt;strong&gt;lexes, parses, validates and executes&lt;/strong&gt; a GraphQL request. It requires a &lt;code&gt;schema&lt;/code&gt; and a &lt;code&gt;requestString&lt;/code&gt;. Optional arguments include a &lt;code&gt;rootValue&lt;/code&gt;, which will get passed as the root value to the executor, a &lt;code&gt;contextValue&lt;/code&gt;, which will get passed to all resolve functions, &lt;code&gt;variableValues&lt;/code&gt;, which will get passed to the executor to provide values for any variables in &lt;code&gt;requestString&lt;/code&gt;, and &lt;code&gt;operationName&lt;/code&gt;, which allows the caller to specify which operation in &lt;code&gt;requestString&lt;/code&gt; will be run, in cases where &lt;code&gt;requestString&lt;/code&gt; contains multiple top-level operations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  And you may ask yourself How do I work this?
&lt;/h4&gt;

&lt;p&gt;We've pulled back a layer of the GraphQL onion and found that there are four primary concerns for the main entrypoint to the reference implementation: lexing, parsing, validating, and executing. &lt;em&gt;&lt;strong&gt;BUT WHAT DOES IT MEAN?&lt;/strong&gt;&lt;/em&gt; Let's dig in to each of those at a high level.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lexing&lt;/strong&gt; turns the strings into tokens that are used by the parser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parsing&lt;/strong&gt; turns the tokens from the lexer into a Document AST.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validating&lt;/strong&gt; traverses the Document AST to ensure proper AST structure and enforce the type system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Executing&lt;/strong&gt; executes the validated Document AST.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, if you had the "basic familiarity with GraphQL concepts" I was assuming last article, you have probably not spent much time in the &lt;code&gt;graphql/language&lt;/code&gt; &lt;a href="https://graphql.org/graphql-js/language/"&gt;module &lt;/a&gt; that is pivotal to those first three concerns. Let's change that.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Fun with Parsing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Have you heard about AST explorer (&lt;a href="https://astexplorer.net/"&gt;site&lt;/a&gt; and &lt;a href="https://github.com/fkling/astexplorer"&gt;github&lt;/a&gt;)? It's a'ight, you know, if you like being able to see how your GraphQL queries get parsed into Document ASTs. We can go ahead and copy over the query we came up with last time.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query aclTasks($user_id: ID!){
  Task(filter: {visibleTo_some: {userId: $user_id}}) {
    taskId
    name
    details
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Cool! Take a few minutes, hours, days, or weeks to wrap your head around what your queries become. Play around with it. Parsing works with more than query/mutation operations. Try throwing your type, directive, and schema definitions at it, too.&lt;/p&gt;

&lt;p&gt;Depending how deep down the rabbit hole you want to go, you can consult a mix of the &lt;a href="http://spec.graphql.org/"&gt;GraphQL Specification&lt;/a&gt; and the &lt;a href="https://github.com/graphql/graphql-js/blob/master/src/language/ast.js"&gt;actual definitions of AST nodes&lt;/a&gt; in the JavaScript reference implementation.&lt;/p&gt;
&lt;h4&gt;
  
  
  Back to business
&lt;/h4&gt;

&lt;p&gt;Alright, what did we notice? Here are a few of my takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The root node of whatever you're parsing is the &lt;code&gt;DocumentNode&lt;/code&gt;, and its only children are &lt;code&gt;DefinitionNode&lt;/code&gt;s in an array labeled &lt;code&gt;definitions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Our queries, mutations, and subscriptions show up as &lt;code&gt;OperationDefinition&lt;/code&gt; nodes.&lt;/li&gt;
&lt;li&gt;Some of the arguments from &lt;code&gt;graphql()&lt;/code&gt; make a little more sense. For instance, if you add multiple query or mutation blocks, you see more than one &lt;code&gt;OperationDefinition&lt;/code&gt; nodes. Your executor needs you to tell it which one to run. 

&lt;ul&gt;
&lt;li&gt;This could be pretty cool down the road. Imagine what we might do if we could define and use extraneous query blocks for some other purpose in the background or even as inputs into resolving the primary operation? &lt;em&gt;&lt;strong&gt;IMAGINE!&lt;/strong&gt;&lt;/em&gt; That might be a topic for another series.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The first &lt;code&gt;selectionSet&lt;/code&gt; within the &lt;code&gt;OperationDefinition&lt;/code&gt; will hold &lt;code&gt;Field&lt;/code&gt;s that are representative of the fields defined in our schema's root &lt;code&gt;Query&lt;/code&gt;, &lt;code&gt;Mutation&lt;/code&gt;, and &lt;code&gt;Subscription&lt;/code&gt; types.&lt;/li&gt;
&lt;li&gt;Each &lt;code&gt;Field&lt;/code&gt; has an optional attribute of &lt;code&gt;arguments&lt;/code&gt;, which contains an array of &lt;code&gt;ArgumentNode&lt;/code&gt;s. This is where our filter arguments show up.&lt;/li&gt;
&lt;li&gt;The value of our filter arguments are of type &lt;code&gt;ObjectFieldNode&lt;/code&gt;, which are a kind of key-value data structure. The keys of these objects are &lt;code&gt;NameNode&lt;/code&gt;s, and the values are &lt;code&gt;ValueNode&lt;/code&gt;s. Complex filter arguments might be nested several levels deep.&lt;/li&gt;
&lt;li&gt;Our &lt;code&gt;OperationDefinition&lt;/code&gt; nodes don't give us any schema-related type info for the &lt;code&gt;Fields&lt;/code&gt; it contains. If we want to define a schema directive on our type definitions to trigger this filter behavior, we are going to have to find a way to somehow access that type info.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Thinking About a Potential Implementation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We're getting very close to fully conceptualizing the steps that will need to occur in the implementation of our discretionary access control directive. Let's lay them out.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;By looking at the internals of &lt;code&gt;neo4jgraphql&lt;/code&gt;, we can see it uses the &lt;code&gt;resolveInfo&lt;/code&gt; argument. That thing seems to have &lt;a href="https://www.prisma.io/blog/graphql-server-basics-demystifying-the-info-argument-in-graphql-resolvers-6f26249f613a"&gt;the pieces we need&lt;/a&gt; to get this done.

&lt;ul&gt;
&lt;li&gt;We could use the &lt;code&gt;resolveInfo&lt;/code&gt; from the resolver functions, or we could preemptively create the parts we need by &lt;a href="https://grandstack.io/docs/neo4j-graphql-js-middleware-authorization.html#middleware"&gt;applying middleware&lt;/a&gt; that somehow feeds into the resolver context.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;GraphQL queries can be written in all sorts of shapes, sizes, and permutations. That's kinda the point. We're going to need some sort of recursion to hit all relevant parts of the &lt;code&gt;OperationDefinition&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bad Joke Break&lt;/strong&gt;: What did the recursive process say to the AST? &lt;em&gt;I'll get to the bottom of this!&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;As we're traversing, we could create a parallel &lt;code&gt;OperationDefinition&lt;/code&gt; AST with modified filter arguments. We can use the &lt;code&gt;schema&lt;/code&gt; field of &lt;code&gt;resolveInfo&lt;/code&gt; to identify which types have the schema directive we'd like to indicate this behavior.&lt;/li&gt;
&lt;li&gt;Replace the old &lt;code&gt;operation&lt;/code&gt; value of &lt;code&gt;resolveInfo&lt;/code&gt; with the transformed &lt;code&gt;OperationDefinition&lt;/code&gt; node when passing it to &lt;code&gt;neo4jgraphql&lt;/code&gt; in your root resolvers, and let &lt;code&gt;neo4jgraphql&lt;/code&gt; do its thing without interference.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  Saving yourself some work
&lt;/h4&gt;

&lt;p&gt;Hey! You know who's lazy? Me.&lt;/p&gt;

&lt;p&gt;It turns out that #2 and #3 are problems that have already been solved. Remember how I said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Validating&lt;/strong&gt; traverses the Document AST to ensure proper AST structure and enforce the type system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sounds kinda, sorta, a little bit like what we're wanting to do, no? Let's put it side-by-side.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validation traverses the AST, examines the contents of each node relative to the type system, identifies features that need to exist or not exist in each node, and collects a record of that identification in the form of error values.&lt;/li&gt;
&lt;li&gt;Transformation traverses the AST, examines the contents of each node relative to the type system, identifies features that need to exist or not exist in each node, and collects a record of that identification in the form of modified nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yep. Checks out to me. Let's &lt;a href="https://github.com/graphql/graphql-js/blob/master/src/validation/validate.js"&gt;take a look&lt;/a&gt;, and...&lt;/p&gt;
&lt;h4&gt;
  
  
  That might just work!
&lt;/h4&gt;

&lt;p&gt;Now we circle back to the comments I made up top about being a little selfish by not just using some existing Apollo tooling. I've taken the liberty of porting over the &lt;code&gt;validation&lt;/code&gt; implementation to a transformation context.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/imkleats"&gt;
        imkleats
      &lt;/a&gt; / &lt;a href="https://github.com/imkleats/graphql-ast-tools"&gt;
        graphql-ast-tools
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Rule-based translation of GraphQL Document ASTs to ASTs of other query languages
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;This is the pattern I'm going to use to implement our filter argument transformations next time. At a very high level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It uses &lt;code&gt;visit()&lt;/code&gt; for depth first traversal, &lt;code&gt;visitWithTypeInfo()&lt;/code&gt; for access to the type info from our schema, and &lt;code&gt;visitInParallel()&lt;/code&gt; to run multiple &lt;a href="https://graphql.org/graphql-js/language/#visitor"&gt;visitor functions&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;These visitor functions allow for separation of concerns within and across certain kinds of AST nodes.&lt;/li&gt;
&lt;li&gt;Instead of collecting an array of error values, we can collect pieces of a transformed AST in a map that allows for lazy evaluation once traversal is complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The road goes ever on and on.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Thanks for joining me on this foray into some GraphQL concepts and implementation details that you might never have wanted to see! We've gone end-to-end to identify some key considerations in query transformation, and I've introduced the structure of a solution I will continue fleshing out.&lt;/p&gt;

&lt;p&gt;Now, when we start building the transformation rules and visitor functions we need, I hope you're able to understand what we're doing and &lt;em&gt;why&lt;/em&gt; we're doing it. Till next time!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>neo4j</category>
      <category>grandstack</category>
      <category>node</category>
    </item>
    <item>
      <title>GRANDstack Access Control - Basics and Concepts</title>
      <dc:creator>Ian Kleats</dc:creator>
      <pubDate>Fri, 21 Feb 2020 06:39:04 +0000</pubDate>
      <link>https://dev.to/imkleats/grandstack-access-control-basics-and-concepts-4phd</link>
      <guid>https://dev.to/imkleats/grandstack-access-control-basics-and-concepts-4phd</guid>
      <description>&lt;p&gt;Hey there. Thank you for joining me on a journey of exploration and discovery into unlocking some of the most powerful features of the &lt;a href="https://grandstack.io"&gt;GRANDstack&lt;/a&gt;! By the end of this series, we'll be able to implement fine-grained discretionary access control features into the GraphQL endpoint generated by &lt;a href="https://github.com/neo4j-graphql/neo4j-graphql-js"&gt;neo4j-graphql-js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cool, right? I thought so too.&lt;/p&gt;

&lt;h4&gt;
  
  
  Before we dive in...
&lt;/h4&gt;

&lt;p&gt;First off, this series assumes some basic familiarity with GraphQL concepts and the GRANDstack itself (&lt;strong&gt;G&lt;/strong&gt;raphQL, &lt;strong&gt;R&lt;/strong&gt;eact, &lt;strong&gt;A&lt;/strong&gt;pollo, &lt;strong&gt;N&lt;/strong&gt;eo4j &lt;strong&gt;D&lt;/strong&gt;atabase). Most important of those GRANDstack topics will be its support for complex nested filtering. Luckily, there's a good &lt;a href="https://blog.grandstack.io/complex-graphql-filtering-with-neo4j-graphql-js-aef19ad06c3e"&gt;blog post&lt;/a&gt; to get you up to speed.&lt;/p&gt;

&lt;p&gt;Second, &lt;strong&gt;this is not a full-fledged tutorial&lt;/strong&gt;. . . &lt;em&gt;yet&lt;/em&gt;. The posts in this series are as much a learning log to document these concepts being developed in real time as they are to invite others to think about and share their own approaches. Learning can be messy. Let's get messy together.&lt;/p&gt;

&lt;h4&gt;
  
  
  And back to the action...
&lt;/h4&gt;

&lt;p&gt;Ok, let's start small. You know what's small? A boring old To-Do app.&lt;/p&gt;

&lt;p&gt;(&lt;em&gt;Wait, you promised an epic journey of awesomeness and are giving me some crappy To-Do app?!?!?&lt;/em&gt;  For now at least, yes.)&lt;/p&gt;

&lt;p&gt;We've heard about this thing called the GRANDstack. It has a lot of synergy out of the box. All you really need to get your backend up is your GraphQL type definitions (i.e. the data model). &lt;code&gt;neo4j-graphql-js&lt;/code&gt; will generate the executable schema from there, which can be served by &lt;code&gt;apollo-server&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ignoring the custom mutation you might use for user login, your type definitions might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
type User {
  ID: ID!
  firstName: String
  lastName: String
  email: String!
  todoList: [Task] @relation(name: "TO_DO", direction: "OUT")
}
type Task {
  ID: ID!
  name: String!
  details: String
  location: Point
  complete: Boolean!
  assignedTo: User @relation(name: "TO_DO", direction: "IN")
}
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cool beans. We have Users that can be assigned Tasks. Our tasks even take advantage of &lt;code&gt;neo4j-graphql-js&lt;/code&gt; &lt;a href="https://grandstack.io/docs/graphql-spatial-types.html"&gt;Spatial Types&lt;/a&gt; that could be useful in the future!&lt;/p&gt;

&lt;p&gt;Let's run it and...&lt;/p&gt;

&lt;h4&gt;
  
  
  What went wrong?
&lt;/h4&gt;

&lt;p&gt;Oh, your app works great. That is, if you wanted Bob down the street to see that you need to stop by the pharmacy to pick up some hemorrhoid cream.&lt;/p&gt;

&lt;p&gt;We could use the &lt;code&gt;@additionalLabels&lt;/code&gt; &lt;a href="https://grandstack.io/docs/neo4j-graphql-js-middleware-authorization.html#additionallabels"&gt;directive&lt;/a&gt; on &lt;code&gt;Task&lt;/code&gt; to keep them accessible to only one &lt;code&gt;User&lt;/code&gt;, but that's kind of limited. What if your mom was going to the pharmacy anyway? Maybe you want &lt;em&gt;certain&lt;/em&gt; people to be able to see certain tasks.&lt;/p&gt;

&lt;p&gt;Maybe you want discretionary access control.&lt;/p&gt;

&lt;p&gt;Unfortunately, I am not aware of any clear cut fine-grained access control options for GRANDstack out of the box. If I were, this post would not exist. On the bright side, we get to explore the possibilities together!&lt;/p&gt;

&lt;h4&gt;
  
  
  Filter to the rescue!
&lt;/h4&gt;

&lt;p&gt;I might have mentioned how GRANDstack &lt;strong&gt;does&lt;/strong&gt; have out-of-the-box support for complex nested filtering. Could this be the answer we seek? (HINT: I think so.)&lt;/p&gt;

&lt;p&gt;Nested filtering means that we can filter the results of any field within our query by the fields of its related types. Those fields of its related types could lead to yet other filterable related types. Ad infinitum.&lt;/p&gt;

&lt;p&gt;I don't actually think we need to go on forever. We just need to realize that the  access control list for our business data is itself a graph connected to our primary data model.&lt;/p&gt;

&lt;p&gt;We &lt;em&gt;could&lt;/em&gt; do this with an arbitrarily complex authorization layer, but instead we're going to keep it simple. Let's reduce the access control structure to a single relationship that sits between the &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Task&lt;/code&gt; types. Our updated type definitions might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
type User {
  userId: ID!
  firstName: String
  lastName: String
  email: String!
  taskList: [Task] @relation(name: "TO_DO", direction: "OUT")
  visibleTasks: [Task] @relation(name: "CAN_READ", direction: "IN")
}
type Task {
  taskId: ID!
  name: String!
  details: String
  location: Point
  complete: Boolean!
  assignedTo: User @relation(name: "TO_DO", direction: "IN")
  visibleTo: [User] @relation(name: "CAN_READ", direction: "OUT")
}
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following filter arguments could then form the basis for locking down our assets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query aclTasks($user_id: ID!){
  Task(filter: {visibleTo_some: {userId: $user_id}}) {
    ...task fields
  }
  User {
    taskList(filter: {visibleTo_some: {userId: $user_id}} {
      ...task fields
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there are other filters that need to be applied, we can wrap them all with an &lt;code&gt;AND&lt;/code&gt; clause:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query aclTasks($user_id: ID!){
  Task(filter: {AND: [{visibleTo_some: {userId: $user_id}},
                     {location_distance_lt: {...}}]}) {
    ...task fields
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Moving ahead in our journey
&lt;/h4&gt;

&lt;p&gt;Oh, I'm sorry. Did I miss something? Your nosy neighbor Bob can still see your pharmaceutical needs can't he because he's savvy enough to submit his own queries without those filters. That dog!&lt;/p&gt;

&lt;p&gt;Next time we'll need to figure out how to use a new schema directive to automate the transformation of our GraphQL filter arguments. This will do more to keep Bob out and also keep the queries on the client side a little cleaner. Till then!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>neo4j</category>
      <category>grandstack</category>
      <category>node</category>
    </item>
  </channel>
</rss>
