question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

DataStore with @auth - Sync error subscription failed ... Missing field argument owner

See original GitHub issue

tl;dr Is it necessary to configure DataStore to include owner for syncing when using owner auth? If so, what’s the syntax or can anyone point to a working example?

Which Category is your question related to?

Amplify CLI, DataStore, auth, GraphQL API

Amplify CLI Version

4.6.0

What AWS Services are you utilizing?

Amplify CLI, Datastore, AppSync, Cognito User Pools

Provide additional details e.g. code snippets

Hi all, attempting to add simple owner authorization to this DataStore demo https://github.com/sebsto/amplify-datastore-js-e2e .

Changes to the demo repo

@auth directive was added to schema:

enum PostStatus {
  ACTIVE
  INACTIVE
}

type Post @model @auth(rules: [{ allow: owner }]) {
  id: ID!
  title: String!
  rating: Int!
  status: PostStatus!
}

App.js updated for auth:

export default withAuthenticator(App, true);

The usual amplify init, amplify add auth (Cognito User Pools), npm run amplify-modelgen, npm run amplify-push, possibly other commands in there

Signing up and signing in…

Result

Browser fails to sync records giving the following in the console:

[WARN] 21:10.98 DataStore - Sync error subscription failed Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onCreatePost'"}]}

which is followed after ~20 seconds by:

AWSAppSyncRealTimeProvider.ts:506 Uncaught TypeError: Cannot read property 'observer' of undefined
    at AWSAppSyncRealTimeProvider._timeoutStartSubscriptionAck (AWSAppSyncRealTimeProvider.ts:506)
    at AWSAppSyncRealTimeProvider.ts:318

Please note

  • same errors when commenting out the useEffect containing the DataStore.observe(Post).subscribe(...) call and clicking buttons to trigger a DataStore.query() instead, so it seems DataStore is trying to set up subscriptions itself
  • same errors when adding owner to the call to DataStore.save() apart from records created in IndexedDB now showing owner
  • from the AppSync console, querying and mutating Posts as the authenticated user works fine and includes an owner field

So, is it necessary to configure DataStore explicitly to use owner? e.g. an equivalent to API.graphql(graphqlOperation(onUpdateNote, { owner })).subscribe(...) in the GraphQL API? Or should DataStore pick that up automagically and the issue is somewhere else?

(Also wondering, are there any samples/demos/docs using DataStore together with auth yet? I understand it’s early days for DataStore but haven’t found any so far)

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:8
  • Comments:82 (18 by maintainers)

github_iconTop GitHub Comments

17reactions
mdoesburgcommented, Jun 22, 2020

@brene @Ashish-Nanda @undefobj @SwaySway @amhinson @manueliglesias @sammartinez @yuth @iartemiev @elorzafe @UnleashedMind

DataStore @auth directive combinations

Like I said in my previous comment, I am currently working on a React Native app which utilizes the great power of DataStore to allow users to use the app while being offline. With that being said, just like a lot of other people I am running into issues when trying to use DataStore in conjunction with the @auth directive.

When I first read the Amplify docs, I was under the impression that almost all the documented directives would work in conjunction with the DataStore, but unfortunately this doesn’t seem to be the case. (Could we maybe add a separate directives section to the DataStore documentation?)

Problems start to arise (in the form of failing subscriptions) whenever you try and limit operations, or try and layer multiple different authentication methods.

In an effort to help out the AWS Amplify team, and to speed up fixes for these use cases, I tested a variation of different @auth rules in combination with the DataStore. The outcome can be found below.

For the sake of the app we’re working on, which we plan on releasing very soon (fingers crossed), and everyone else wanting to leverage the power of DataStore but requires slightly more complex @auth directive usage beyond a single user or multiple users that have full access to every operation, hopefully this helps even a little bit.

Extra context

Library versions:

These steps were performed with/before each test:

  1. Log users out of iOS and Android simulators
  2. Modify schema
  3. Run amplify push
  4. Run amplify codegen models
  5. Reload devices
  6. Log in with 2 different users
  7. Observe model on DataStore
  8. Try creating/updating new model from both devices

If applicable to schema, the following steps were also performed:

  • Try creating/updating new model from AppSync console (logged in as one of the users)
  • Try creating/updating new model from AppSync console (logged in as a user part of the “Admin” group)
  • Try creating/updating new model from Lambda (IAM)

Schema’s

Only 5/14 schema’s work as expected. I am particularly interested in limiting operations for an owner, while allowing the owner to receive updates for all operations, and having IAM authentication in combination with the owner rule. I was unable to get any subscriptions to work when layering an IAM auth rule on top of an owner rule.

  • Schema 1 (works) { allow: owner }
  • Schema 2 { allow: owner, operations: [create, update, delete] }
  • Schema 3 { allow: owner, operations: [create, update, delete] } { allow: private, operations: [read] }
  • Schema 4 { allow: owner } { allow: private, provider: iam }
  • Schema 5 (works) { allow: owner } { allow: groups, groups: [“Admin”] }
  • Schema 6 { allow: owner, operations: [create, read] } { allow: groups, groups: [“Admin”] }
  • Schema 7 { allow: owner, operations: [create, read, update] } { allow: groups, groups: [“Admin”] }
  • Schema 8 (works) { allow: owner, identityClaim: “custom:user_id” } { allow: groups, groups: [“Admin”] }
  • Schema 9 { allow: owner, identityClaim: “custom:user_id”, operations: [create, read, update] } { allow: groups, groups: [“Admin”] }
  • Schema 10 { allow: owner } { allow: private, provider: iam } { allow: groups, groups: [“Admin”] }
  • Schema 11 { allow: owner } { allow: owner, ownerField: “editors”, operations: [update, read] }
  • Schema 12 { allow: owner, identityClaim: “custom:user_id” } { allow: groups, groups: [“Admin”] }
  • Schema 13 (works) { allow: groups, groups: [“Member”], operations: [read] } { allow: groups, groups: [“Admin”] }
  • Schema 14 (works) subscriptions: { level: public } { allow: owner, operations: [create, read] } { allow: groups, groups: [“Admin”] }

Schema 1 (works) #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent(owner: String!): SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent(owner: String!): SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent(owner: String!): SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema works as expected.

Schema 2 #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner, operations: [create, update, delete] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent: SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent: SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent: SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema doesn’t work as expected. Subscriptions fail, and result in the following warnings/errors:

[WARN] 38:14.669 DataStore - Connection failed: {"errors":[{"message":"Validation error of type UnknownArgument: Unknown field argument owner @ 'onDeleteSharedContent'"}]}
[WARN] 38:14.756 DataStore - Connection failed: {"errors":[{"message":"Validation error of type UnknownArgument: Unknown field argument owner @ 'onUpdateSharedContent'"}]}
[WARN] 38:14.802 DataStore - Connection failed: {"errors":[{"message":"Validation error of type UnknownArgument: Unknown field argument owner @ 'onCreateSharedContent'"}]}

Schema 3 #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner, operations: [create, update, delete] },
    { allow: private, operations: [read] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent: SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent: SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent: SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema doesn’t work as expected. Subscriptions fail, and result in the following warnings/errors:

[WARN] 53:08.331 DataStore - Connection failed: {"errors":[{"message":"Validation error of type UnknownArgument: Unknown field argument owner @ 'onCreateSharedContent'"}]}
[WARN] 53:08.358 DataStore - Connection failed: {"errors":[{"message":"Validation error of type UnknownArgument: Unknown field argument owner @ 'onDeleteSharedContent'"}]}
[WARN] 53:08.413 DataStore - Connection failed: {"errors":[{"message":"Validation error of type UnknownArgument: Unknown field argument owner @ 'onUpdateSharedContent'"}]}

Schema 4 #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner },
    { allow: private, provider: iam }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent(owner: String!): SharedContent @aws_subscribe(mutations: ["createSharedContent"]) @aws_iam @aws_cognito_user_pools
onUpdateSharedContent(owner: String!): SharedContent @aws_subscribe(mutations: ["updateSharedContent"]) @aws_iam @aws_cognito_user_pools
onDeleteSharedContent(owner: String!): SharedContent @aws_subscribe(mutations: ["deleteSharedContent"]) @aws_iam @aws_cognito_user_pools

This schema doesn’t work as expected. Subscriptions fail, and result in the following warnings/errors:

[WARN] 26:54.58 DataStore - Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onDeleteSharedContent'"}]}
[WARN] 26:54.97 DataStore - Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onCreateSharedContent'"}]}
[WARN] 26:54.156 DataStore - Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onUpdateSharedContent'"}]}

Schema 5 (works) #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner },
    { allow: groups, groups: ["Admin"] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema works as expected.

Schema 6 #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner, operations: [create, read] },
    { allow: groups, groups: ["Admin"] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema doesn’t work as expected. The onDeleteSharedContent and onUpdateSharedContent subscriptions fail. The result is the following warnings/errors:

[WARN] 33:56.520 DataStore - Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onDeleteSharedContent on type Subscription"}]}
[WARN] 33:56.553 DataStore - Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onUpdateSharedContent on type Subscription"}]}

I guess in this case, the subscriptions failing could be seen as “intended” since the owner doesn’t have the update and delete operations, but I feel like a more common use case would be that the owner can’t run the update and delete mutations, but still has access to the onUpdate and onDelete subscriptions. Maybe introducing something like a “listen” operation, which I saw in a different GitHub issue would be a way to control this behaviour separately?

Schema 7 #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner, operations: [create, read, update] },
    { allow: groups, groups: ["Admin"] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema doesn’t work as expected. The onDeleteSharedContent subscription fails, and result in the following warnings/errors:

[WARN] 51:55.649 DataStore - Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onDeleteSharedContent on type Subscription"}]}

Same as in Schema 6, the subscription failing could be seen as “intended” since the owner doesn’t have the delete operation, but I feel like a more common use case would be that the owner can’t run the delete mutation, but still has access to the onDelete subscriptions. Maybe introducing something like a “listen” operation, which I saw in a different GitHub issue would be a way to control this behaviour separately?

Schema 8 (works) #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner, identityClaim: "custom:user_id" },
    { allow: groups, groups: ["Admin"] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Requires you to pass an idToken instead of an accessToken in Amplify configure:

Amplify.configure({
  ...awsConfig,
  graphql_headers: async () => {
    try {
      const session = await Auth.currentSession();
      const token = session.idToken.jwtToken;

      return { Authorization: token };
    } catch {}
  },
});

Generates the following subscriptions:

onCreateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema works as expected.

Schema 9 #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner, identityClaim: "custom:user_id", operations: [create, read, update] },
    { allow: groups, groups: ["Admin"] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Requires you to pass an idToken instead of an accessToken in Amplify configure:

Amplify.configure({
  ...awsConfig,
  graphql_headers: async () => {
    try {
      const session = await Auth.currentSession();
      const token = session.idToken.jwtToken;

      return { Authorization: token };
    } catch {}
  },
});

Generates the following subscriptions:

onCreateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema doesn’t work as expected. The onDeleteSharedContent subscription fails, and result in the following warnings/errors:

[WARN] 37:22.453 DataStore - Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onDeleteSharedContent on type Subscription"}]}

Same as in Schema 6 & 7, the subscription failing could be seen as “intended” since the owner doesn’t have the delete operation, but I feel like a more common use case would be that the owner can’t run the delete mutation, but still has access to the onDelete subscriptions. Maybe introducing something like a “listen” operation, which I saw in a different GitHub issue would be a way to control this behaviour separately?

Schema 10 #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner },
    { allow: private, provider: iam },
    { allow: groups, groups: ["Admin"] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["createSharedContent"]) @aws_iam @aws_cognito_user_pools
onUpdateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["updateSharedContent"]) @aws_iam @aws_cognito_user_pools
onDeleteSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["deleteSharedContent"]) @aws_iam @aws_cognito_user_pools

This schema doesn’t work as expected. Subscriptions work, but users see other user’s content. Queries properly return only the owner’s content.

Schema 11 #

Similar to example from docs: https://docs.amplify.aws/cli/graphql-transformer/directives#multiple-authorization-rules

type SharedContent
  @model
  @auth(rules: [
    { allow: owner },
    { allow: owner, ownerField: "editors", operations: [update, read] }
  ])
{
  id: ID!
  content: String
  owner: String
  editors: [String]
}

Generates the following subscriptions:

onCreateSharedContent(owner: String!, editors: String!): SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent(owner: String!, editors: String!): SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent(owner: String!, editors: String!): SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema doesn’t work as expected. Subscriptions fail, and result in the following warnings/errors:

[WARN] 17:46.494 DataStore - Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onUpdateSharedContent'"}]}
[WARN] 17:46.579 DataStore - Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument editors @ 'onDeleteSharedContent'"}]}
[WARN] 17:46.627 DataStore - Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument editors @ 'onCreateSharedContent'"}]}

Schema 12 #

type SharedContent
  @model
  @auth(rules: [
    { allow: owner, identityClaim: "custom:user_id" },
    { allow: groups, groups: ["Admin"] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent(owner: String): SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema doesn’t work as expected. Subscriptions fail, and result in the following warnings/errors:

[WARN] 15:09.631 DataStore - Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onCreateSharedContent on type Subscription"}]}
[WARN] 15:09.700 DataStore - Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onUpdateSharedContent on type Subscription"}]}
[WARN] 15:09.741 DataStore - Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onDeleteSharedContent on type Subscription"}]}

Schema 13 (works) #

Based on recent fix: https://github.com/aws-amplify/amplify-cli/pull/4340

type SharedContent
  @model
  @auth(rules: [
    { allow: groups, groups: ["Member"], operations: [read] },
    { allow: groups, groups: ["Admin"] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent: SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent: SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent: SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema works as expected, but the recent fix only seems relevant if you use group auth.

Schema 14 (works) #

type SharedContent
  @model(subscriptions: { level: public })
  @auth(rules: [
    { allow: owner, operations: [create, read] },
    { allow: groups, groups: ["Admin"] }
  ])
{
  id: ID!
  content: String
  owner: String
}

Generates the following subscriptions:

onCreateSharedContent: SharedContent @aws_subscribe(mutations: ["createSharedContent"])
onUpdateSharedContent: SharedContent @aws_subscribe(mutations: ["updateSharedContent"])
onDeleteSharedContent: SharedContent @aws_subscribe(mutations: ["deleteSharedContent"])

This schema works as expected, and is useful if you don’t care that your subscriptions are public.

11reactions
manueliglesiascommented, Jun 24, 2020

Thank you @mdoesburg

I just want to post an update here to let you know that we are looking into this, thank you so much for the super thorough breakdown!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Developers - DataStore with @auth - Sync error subscription failed ...
DataStore with @auth - Sync error subscription failed ... Missing field argument owner.
Read more >
Unknown field argument owner @ 'onCreateXYZ' - Science Fare
The code generator for AppSync gets confused in this case and creates incorrect Subscription definitions. They lack the `owner` parameter, as ...
Read more >
Azure AD authentication & authorization error codes
AuthenticationFailed - Authentication failed for one of the following reasons: The subject name of the signing certificate isn't authorized; A ...
Read more >
Troubleshooting and Common Mistakes - AWS AppSync
If your GraphQL operation returns the following error message, it may be because your request mapping template structure doesn't match the Amazon DynamoDB ......
Read more >
DataStore - subscriptionError, Connection failed
I found a solution on a GitHub forum: https://github.com/aws-amplify/amplify-js/issues/4535#issuecomment-589594827.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found