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

Access control for subscriptions

Try it yourself

You can find code example for this chapter here.

So far we've talked about why access control is important for subscriptions, but we haven't looked into how to implement it. For this, we'll use a simple setup with 3 users in 2 different groups and we'll make sure that each user can only get events from its own group but not from the other group. management

Users in groups

For subscription events, we'll use the example from the previous chapter where there is a todo subscription that gets a userId and a groupId argument.

type TodoEvent {
  userId: ID!
  groupId: ID!
  todoId: ID!
  todo: Todo
}

type Subscription {
  todo(userId: ID, groupId: ID): TodoEvent
  @aws_subscribe(mutations: ["notifyTodo"])
}

To secure this subscription, we'll need to implement a couple of restrictions:

  • Either the userId or the groupId argument is required
  • The userId must be in the same group as the caller User
  • The groupId must be the caller's group

Everything related to subscriptions is implemented in the response mapping template for the subscription field's resolver. So every code we write will be for the Subscription.todo field.

We'll cover a universal approach based on validating the arguments that works with any filtering method, then we'll see a different way that require enhanced filtering.

Argument validation

The idea behing this access control implementation is to check the arguments the client sent and reject the subscription if it is for events that should not be sent to that client. In our example, if the clients sends a subscription with a different group, then it should be rejected.

For example, let's log in with user1, which is in group1 (the password is Password.1):

Login with user1/Password.1

Then a subscription with groupId: "group2":

subscription MySubscription {
  todo(groupId: "group2") {
    todoId
    userId
    groupId
  }
}

The subscription is rejected:

Error: {
  "errors": [
    {
      "message": "Connection failed: {
        \"errors\":[{
          \"errorType\":\"Unauthorized\",
          \"message\":\"Not Authorized to access todo on type Subscription\"
        }]
      }"
    }
  ]
}

To implement this and the other requirements, we need a pipeline resolver for the Subscription.todo field as it needs to fetch two users from the database.

Subscription.todo implementation

Since the implementation needs to handle all cases, let's break it down according to the three cases!

  • When there is neither a userId nor a groupId supplied, the result is an error
  • If there is a userId argument, fetch that and the current user, then compare the groupIds
  • If there is only a groupId argument, fetch the current user then compare the groupIds
Different cases separated
No-arguments case

Since a subscription without any arguments receives all events, it is crucial to handle this case. Usually, a simple check in the first function with an explicit reject is enough.

Code example

The implementation for this resolver is here.

The first function's request implementation:

There is more, but you've reached the end of this preview
Read this and all other chapters in full and get lifetime access to:
  • all future updates
  • full web-based access
  • PDF and Epub versions