Amplify-cli: subscribing to models requires update operation

Created on 11 Nov 2019  路  13Comments  路  Source: aws-amplify/amplify-cli

Describe the bug
Our model contains Projects, that unauthenticated users of a mobile app should be able to read, and also to subscribe to updates to these objects. Hence our graphql schema contains:

type Project
  @model(subscriptions: { level: public })
  @auth(
    rules: [
      {
        allow: private
        provider: userPools
        operations: [read, create, update, delete]
      }
      { allow: public, provider: iam, operations: [read] }
    ]
  ) {

But when the client tries to subscribe to updates (verifiable also in the AppSync console), an error for unauthorised access is thrown, despite only read access is required, and also subscriptions for the model is set to public. There should be a way for unauthenticated clients to subscribe to public models.

  "errors": [
    {
      "path": [
        "onUpdateProject"
      ],
      "data": null,
      "errorType": "Unauthorized",
      "errorInfo": null,
      "locations": [
        {
          "line": 2,
          "column": 3,
          "sourceName": null
        }
      ],
      "message": "Not Authorized to access onUpdateProject on type Subscription"
    }

The only way to have the proper resource statements generated in the cloudformation scripts for the unauthRole is to include update in the list of operations.

Amplify CLI Version
3.15.0

To Reproduce
see above

Expected behavior
if read access is allowed for public, it should be possible to subscribe to updates

bug graphql-transformer pending-release

Most helpful comment

When multi auth is enabled, the subscriptions support only the default auth type even if its declared as public. The transformer is not generating the required multi auth directives to support all the auth types enabled in your API. I am marking this as bug.

the workaround for this issue is to extend subscription in your schema and adding the auth directives manually as shown below

type Subscription {
    onCreateProjectPublic: Project
        @aws_subscribe(mutations: ["createProject"])
        @aws_iam
        @aws_cognito_user_pools
    onUpdateProjectPublic: Project
        @aws_subscribe(mutations: ["updateProject"])
        @aws_iam
        @aws_cognito_user_pools
    onDeleteProjectPublic: Project
        @aws_subscribe(mutations: ["deleteProject"])
        @aws_iam
        @aws_cognito_user_pools
}

All 13 comments

What is the default Authorization mode for your API? Could you try subscribing to API using the default authorization mode and see if the subscription succeeds

This the backend-config.json

    "api": {
        "fooBarApi": {
            "service": "AppSync",
            "providerPlugin": "awscloudformation",
            "output": {
                "authConfig": {
                    "additionalAuthenticationProviders": [
                        {
                            "authenticationType": "AWS_IAM"
                        }
                    ],
                    "defaultAuthentication": {
                        "authenticationType": "AMAZON_COGNITO_USER_POOLS",
                        "userPoolConfig": {
                            "userPoolId": "xxx"
                        }
                    }
                }
            }
        },

AFAIK there's no unauth access with userpools, is there? so I don't know how to subscribe to the api with the default auth mode.

as far as I can tell, the transformer doesn't generate the required resources in the unauth role to grant access to the subscriptions.

When multi auth is enabled, the subscriptions support only the default auth type even if its declared as public. The transformer is not generating the required multi auth directives to support all the auth types enabled in your API. I am marking this as bug.

the workaround for this issue is to extend subscription in your schema and adding the auth directives manually as shown below

type Subscription {
    onCreateProjectPublic: Project
        @aws_subscribe(mutations: ["createProject"])
        @aws_iam
        @aws_cognito_user_pools
    onUpdateProjectPublic: Project
        @aws_subscribe(mutations: ["updateProject"])
        @aws_iam
        @aws_cognito_user_pools
    onDeleteProjectPublic: Project
        @aws_subscribe(mutations: ["deleteProject"])
        @aws_iam
        @aws_cognito_user_pools
}

The workaround suggested by @yuth worked for me but only after I also added the permission to the UnauthRole policy:
arn:aws:appsync:us-east-1:[...]:apis/[...]/types/Subscription/fields/onUpdateProjectPublic

I made this change directly in the IAM console as I couldn't find a way to do it by editing the Amplify files

Hi @AndreasEK
PR: https://github.com/aws-amplify/amplify-cli/pull/4340 address this by adding read on the permissions the GraphQL Transformer will add the necessary permissions to allow the unauthRole to listen to subscriptions.

The workaround suggested by @yuth worked for me but only after I also added the permission to the UnauthRole policy:
arn:aws:appsync:us-east-1:[...]:apis/[...]/types/Subscription/fields/onUpdateProjectPublic

I made this change directly in the IAM console as I couldn't find a way to do it by editing the Amplify files

@andriworld You can do it in CustomResources.json file:

  ...

  "Resources": {
    "UnauthRolePolicy": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "appsync-unauthrole-policy-custom",
        "Roles": [
          {
            "Ref": "unauthRoleName"
          }
        ],
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": ["appsync:GraphQL"],
              "Resource": [
                {
                  "Fn::Sub": [
                    "arn:aws:appsync:${AWS::Region}:${AWS::AccountId}:apis/${apiId}/types/${typeName}/fields/${fieldName}",
                    {
                      "apiId": {
                        "Ref": "AppSyncApiId"
                      },
                      "typeName": "Subscription",
                      "fieldName": "onUpdateProjectPublic"
                    }
                  ]
                }
              ]
            }
          ]
        }
      }
    }
  },
  ...

Closing this issue as the PR for this has been merged and and released into version 4.21.1. By adding the read operation this will generate the IAM policies to allow access to subscriptions.

Hi @SwaySway, the fix didn't work for my model (amplify CLI version 4.21.3)

type Project @model(subscriptions: { level: public })
 @auth(
    rules: [
      { allow: public, provider: iam, operations: [read] }      
      { allow: owner, operations: [create, read, update ] }
    ]
  ) {

No subscription permissions are added to the IAM policies (and the multiple auth directives are missing from the schema)

I also tested changing the model to this:

type Project @model
 @auth(
    rules: [
      { allow: public, provider: iam, operations: [read] }      
      { allow: owner, operations: [create, read, update ] }
    ]
  ) {

The permissions are added, but now only the owner of a project can subscribe to its updates.
Is there something else I should do?

Thank you

@andriworld Were you able to resovle?

I'm facing the same issue on version 4.26.0 This is my model

type Book 
  @model
  @auth(
    rules: [
      { allow: groups, groups: ["Admins"] }
      { allow: groups, groupsField: "level1", operations: [update, read] }
      { allow: groups, groupsField: "level2", operations: [read] }
    ]

In this case admins can subscribe. but level1 can't.

I am still seeing this same behavior on version 4.29.2 with this model:

type Account @model
    @auth(rules: [
        {
            allow: owner, ownerField: "id", identityField: "custom:accountNumber",
            operations: [read]
        }
        { allow: groups, groups: ["admin"] }
    ])
    {
        id: ID!
        name: String
        description: String
    }

owner can read, but on trying to subscribe to update, get unauthorized error.

@SwaySway Is this expected behavior after the PR merge or have I hit a new case?

Seems like read permission should allow for subscribing to updates.

I'm on 4.29.4.. And am also seeing the same behaviour. I guess I should create a new Issue though

@SwaySway I'm on 4.29.5

type Post
  @model(subscriptions: { level: public })
  @aws_iam
  @aws_cognito_user_pools
  @auth(
    rules: [
      { allow: owner, operations: [create, read, update, delete] }
      { allow: public, provider: iam, operations: [read, update] }
      { allow: groups, groups: ["user"], operations: [create, read, update] }
    ]
  )
  @key(name: "byUser", fields: ["userID"]) {
  id: ID!
  title: String!
  userID: ID!
  content: String
  user: User @connection(fields: ["userID"])
  comments: [Comment] @connection(keyName: "byPost", fields: ["id"])
}

Owner can read, but when it is aws_iam, "no current user"

Was this page helpful?
0 / 5 - 0 ratings