Search code examples
amazon-web-servicessubscriptionaws-appsyncappsync-apollo-client

AWS AppSync Subscriptions: Complex Authorization based on Object with in Updated Document


The object that will be changed by a mutation contains a permissions array that contains user objects that consist of a userId and a write permission boolean. If a user's userId is present in the list, the user has read permission on the object. If write is set to true, the user also has write permission.

This makes modifying the object easier from a mutation perspective, but it makes handling subscriptions much more difficult, since I don't have access to the object being updated at subscription creation. Thus, I am unable to ensure that user's will only get updates to the object if they have the appropriate permissions.

I don't think it makes a difference (since I can't handle this on the client-side securely), but I'm building a React web client.

Is there any feasible way around this?


Solution

  • One possible solution would be to setup a server-side job which subscribes to all new mutations. This server-side listener would receive every new mutation, look into the permissions list, and publish to the authorized user using a None datasource resolver. The users will only be allowed to subscribe to a subscription with their user id.

    The schema would look something like this:

    type Object {
      permissions: [User]
      //.. Other fields
    }
    
    type User {
      userId: ID!
      write: Boolean
    }
    
    // The server listener will populate this
    type PublishPayload {
      userId: ID!
      objectToPublish: Object
    }
    
    type Mutation {
      // The original mutation
      updateObject(): Object
    
      // The server-side listener will use this to publish. Attach a None Resolver to it.
      publishToUser(userId: ID!): PublishPayload
    }
    
    type Subscription {
      // This subscription is used by the server to listen to all updateObject mutations
      serverSubscription(): Object
      @aws_subscribe(mutations:["updateObject"])
    
      // This subscription is used by the users. 
      // You would add a resolver to it that fails authorization if they try to subscribe to a different user.
      userSubscription(userId: ID!): PublishPayload
      @aws_subscribe(mutations:["publishToUser"])
    
    //.. More schema
    

    Hope this helps!