amplify-category-api icon indicating copy to clipboard operation
amplify-category-api copied to clipboard

Field level authorization with multiple owners per field

Open ggorge-etiqa opened this issue 9 months ago • 0 comments

Amplify CLI Version

12.6.0

Question

I'm building a dual approval process in Amplify using AppSync and Cognito auth, where the confirmation of both the two actors, ActorA and ActorB, is needed to consider the process approved. In our scenario only ActorA, aka "sender", can initiate the process and ActorB, aka "recipient", can confirm or reject the approval delayed.

In order to implement that, I'm using

  • field level authorization https://docs.amplify.aws/gen1/javascript/tools/cli-legacy/auth-directive/#field-level-authorization
  • custom ownerField https://docs.amplify.aws/gen1/javascript/build-a-backend/graphqlapi/customize-authorization-rules/#per-user--owner-based-data-access
  • multiple owners per field. Although it works, there is no mention of it in the docs.

With this scenario, the field level authorization is completely handled by amplify autogenerated resolvers. Moreover, I rely on Lambda custom VTL resolvers only for user input data validation and some business logic.

Attached to the Approval DynamoDB table there is a DynamoDB Stream triggered lambda that marks as Approved or Rejected the relevant document status, based on our custom logic.

The schema.grapql looks like:

type Approval @model @auth(rules: [{ allow: owner}]) {
    id: ID! @auth(rules: [{ allow: owner, operations: [update,create,read], ownerField: "senderOwner"},{ allow: owner, operations: [read, update], ownerField: "recipientOwner"}])
    senderOwner: String @auth(rules: [{ allow: owner, operations: [create,read], ownerField: "senderOwner"},{ allow: owner, operations: [read], ownerField: "recipientOwner"}]) @index(name: "senderOwnerIndex", queryField: "getApprovalBysenderOwner")
    recipientOwner: String @auth(rules: [{ allow: owner, operations: [read], ownerField: "senderOwner"},{ allow: owner, operations: [read], ownerField: "recipientOwner"}]) @index(name: "recipientOwnerIndex", queryField: "getApprovalByrecipientOwner")
    documentId: String @auth(rules: [{ allow: owner, operations: [create,read], ownerField: "senderOwner"},{ allow: owner, operations: [read], ownerField: "recipientOwner"}]) @index(name: "documentIdIndex", queryField: "getApprovalByDocumentId")
    senderStatus: String @auth(rules: [{ allow: owner, operations: [read,update], ownerField: "senderOwner"},{ allow: owner, operations: [read], ownerField: "recipientOwner"}])
    recipientStatus: String @auth(rules: [{ allow: owner, operations: [read], ownerField: "senderOwner"},{ allow: owner, operations: [read,update], ownerField: "recipientOwner"}])
}

type Document @model(subscriptions: null) @auth(rules: [{ allow: private, operations: [read] }]) {
  id: ID!
  name: String!
  status: DocumentStatus!
}

enum DocumentStatus {
  new
  approved
  rejected
}

The system works as expected but I'm a little worried because "multiple owners per field" seems a not documented feature. Can I rely on that?

ggorge-etiqa avatar May 13 '24 15:05 ggorge-etiqa