You are viewing the preview version of this book
Click here for the full version.

Implementing access control

Run the example

You can find code example for this chapter here.

We've covered access control in the GraphQL Access Control chapter from the viewpoint of the specification. We've seen how entry points and traversals define what data is available for a client and controlling access to the fields as well as the data returned by the resolvers form the basis of security in GraphQL.

In this chapter, we'll dive deep into the implementation of these access control mechanisms and how AppSync supports them. We'll discuss schema directives, data filtering with resolver functions, and best practices.

As a recap, our data model consists of users, articles, and groups. Articles are all public, while users are constrained to their own groups. A special type of users, administrators, can list all users but only in their groups.

Data model
type User {
  username: String!
  friends: [User]
  group: Group
}

type Group {
  name: String
  users: [User]
}

type Article {
  text: String
  author: User
}

type Query {
  user(username: String!): User
  allUsers: [User]
  allArticles: [Article]
}

The controls we'll implement are:

  1. The Query.allUsers can be called only by administrators

When a regular user makes this query, it will be denied:

query MyQuery {
  allUsers {
    username
  }
}
  1. Query.user can only be called with the current user

This query made by user1 will be denied:

query MyQuery {
  user(username: "user1") {
    username
  }
}
  1. User.group only works when the caller is in the same group

This query made by a user in one group will get group: null for users in a different group:

query MyQuery {
  allArticles {
    author {
      group {
        name
      }
    }
  }
}
  1. Query.allUsers returns only the users in the admin's group

The result of this query won't contain users in other groups:

query MyQuery {
  allUsers {
    username
  }
}

The first one will use a directive in the schema, while the others require resolver implementations.

Example object graph