Closed chuckatc closed 4 years ago
@chuckatc We're actively working on this and expect a fix for this very soon. cc @yuth @elorzafe
I'm hitting this too, or at least something similar, take the following slightly extended example,
Type Task
@model
@auth(rules: [
{allow: groups, groups: ["SuperUser"], queries: [get, list], mutations: [create, update, delete]},
{allow: owner, queries: [get, list], mutations: [create]}
])
{
id: ID!
title: String!
description: String
status: String
}
I'd expect an owner to be able to subscribe to onCreateTask, and get only their 'Tasks', and a user in the SuperUser group to be able to subscribe to all onCreateTask events from all users. As it is today the owner is a required argument to the generated subscription, so when a member of the SuperUser group subscribes with their user as owner they only see their create events not all create events.
EDIT: So playing around a bit more I changed things to the following and it is now working as expected.
Type Task
@model
@auth(rules: [
{allow: groups, groups: ["SuperUser"]},
{allow: owner, queries: [get, list], mutations: [create]}
])
{
id: ID!
title: String!
description: String
status: String
}
I also had to change the auto-generated subscription to remove the argument ($owner: String!)
.
I suspect you can discount my comment, but there appears to be something odd going on here. Let me know if there are some combinations you need me to test to track this down further.
I think I'm hitting something similar to my app. Setup is pretty much the same as the original author, Javascript client, amplify generated backend and models.
Schema is this:
type Timeline
@model
@searchable
@auth(
rules: [
{ allow: groups, groups: ["SuperUser"] }
{ allow: owner }
]
) {
id: ID!
name: String!
startDate: AWSDate!
endDate: AWSDate!
investment401k: [Investment401k]
@connection(name: "TimelineInvestment401ks")
income: [Income] @connection(name: "TimelineIncomes")
}
type Income
@model
@searchable
@auth(
rules: [
{ allow: groups, groups: ["SuperUser"] }
{ allow: owner }
]
) {
id: ID!
startDate: AWSDate!
endDate: AWSDate
rate: Float!
object: AWSJSON
timeline: Timeline! @connection(name: "TimelineIncomes")
}
type Investment401k
@model
@searchable
@auth(
rules: [
{ allow: groups, groups: ["SuperUser"] }
{ allow: owner }
]
) {
id: ID!
object: AWSJSON
timeline: Timeline! @connection(name: "TimelineInvestment401ks")
}
type UserData
@model
@searchable
@auth(
rules: [
{ allow: groups, groups: ["SuperUser"] }
{ allow: owner }
]
) {
id: ID!
birthdate: AWSDate!
retirementdate: AWSDate!
profileImageUrl: String
profileImageUncroppedUrl: String
profileImageManipulations: AWSJSON
}
aws-exports.js, which is generated by Amplify, is this (test environment, nothing production):
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
const awsmobile = {
"aws_project_region": "us-east-1",
"aws_cognito_identity_pool_id": "us-east-1:85e7460b-feab-4f21-87b7-a9a265125c77",
"aws_cognito_region": "us-east-1",
"aws_user_pools_id": "us-east-1_txxH6nvSj",
"aws_user_pools_web_client_id": "7t9mnj8a2pqfrju2e0tjh40ka4",
"oauth": {
"domain": "modelmymoney655c1605-655c1605-localdev.auth.us-east-1.amazoncognito.com",
"scope": [
"phone",
"email",
"openid",
"profile",
"aws.cognito.signin.user.admin"
],
"redirectSignIn": "http://localhost/auth/signin/",
"redirectSignOut": "http://localhost/auth/signout/",
"responseType": "code"
},
"federationTarget": "COGNITO_USER_POOLS",
"aws_appsync_graphqlEndpoint": "https://aitvi3puvfcwfkhqmhmsiw6i3q.appsync-api.us-east-1.amazonaws.com/graphql",
"aws_appsync_region": "us-east-1",
"aws_appsync_authenticationType": "AMAZON_COGNITO_USER_POOLS",
"aws_appsync_apiKey": "da2-g47wpfle4rhzrotlqnfu6cgew4",
"aws_user_files_s3_bucket": "model-my-money947365a9c1734517af86f8ba26db26a7money-localdev",
"aws_user_files_s3_bucket_region": "us-east-1"
};
export default awsmobile;
Relevant lines from main.js
import Amplify from 'aws-amplify';
import awsconfig from '@/aws-exports';
Amplify.configure(awsconfig);
And the generated schema.js in the /models/ folder:
export const schema = {
"models": {
"Timeline": {
"syncable": true,
"name": "Timeline",
"pluralName": "Timelines",
"attributes": [
{
"type": "model",
"properties": {}
},
{
"type": "searchable",
"properties": {}
},
{
"type": "auth",
"properties": {
"rules": [
{
"groupClaim": "cognito:groups",
"provider": "userPools",
"allow": "groups",
"groups": [
"SuperUser"
],
"operations": [
"create",
"update",
"delete"
]
},
{
"provider": "userPools",
"ownerField": "owner",
"allow": "owner",
"identityClaim": "cognito:username",
"operations": [
"create",
"update",
"delete"
]
}
]
}
}
],
"fields": {
"id": {
"name": "id",
"isArray": false,
"type": "ID",
"isRequired": true,
"attributes": []
},
"name": {
"name": "name",
"isArray": false,
"type": "string",
"isRequired": true,
"attributes": []
},
"startDate": {
"name": "startDate",
"isArray": false,
"type": "AWSDate",
"isRequired": true,
"attributes": []
},
"endDate": {
"name": "endDate",
"isArray": false,
"type": "AWSDate",
"isRequired": true,
"attributes": []
},
"investment401k": {
"name": "investment401k",
"isArray": true,
"type": {
"model": "Investment401k"
},
"isRequired": false,
"attributes": [],
"association": {
"connectionType": "HAS_MANY",
"associatedWith": "timeline"
}
},
"income": {
"name": "income",
"isArray": true,
"type": {
"model": "Income"
},
"isRequired": false,
"attributes": [],
"association": {
"connectionType": "HAS_MANY",
"associatedWith": "timeline"
}
}
}
},
"Investment401k": {
"syncable": true,
"name": "Investment401k",
"pluralName": "Investment401ks",
"attributes": [
{
"type": "model",
"properties": {}
},
{
"type": "searchable",
"properties": {}
},
{
"type": "auth",
"properties": {
"rules": [
{
"groupClaim": "cognito:groups",
"provider": "userPools",
"allow": "groups",
"groups": [
"SuperUser"
],
"operations": [
"create",
"update",
"delete"
]
},
{
"provider": "userPools",
"ownerField": "owner",
"allow": "owner",
"identityClaim": "cognito:username",
"operations": [
"create",
"update",
"delete"
]
}
]
}
}
],
"fields": {
"id": {
"name": "id",
"isArray": false,
"type": "ID",
"isRequired": true,
"attributes": []
},
"object": {
"name": "object",
"isArray": false,
"type": "AWSJSON",
"isRequired": false,
"attributes": []
},
"timeline": {
"name": "timeline",
"isArray": false,
"type": {
"model": "Timeline"
},
"isRequired": true,
"attributes": [],
"association": {
"connectionType": "BELONGS_TO",
"targetName": "investment401kTimelineId"
}
}
}
},
"Income": {
"syncable": true,
"name": "Income",
"pluralName": "Incomes",
"attributes": [
{
"type": "model",
"properties": {}
},
{
"type": "searchable",
"properties": {}
},
{
"type": "auth",
"properties": {
"rules": [
{
"groupClaim": "cognito:groups",
"provider": "userPools",
"allow": "groups",
"groups": [
"SuperUser"
],
"operations": [
"create",
"update",
"delete"
]
},
{
"provider": "userPools",
"ownerField": "owner",
"allow": "owner",
"identityClaim": "cognito:username",
"operations": [
"create",
"update",
"delete"
]
}
]
}
}
],
"fields": {
"id": {
"name": "id",
"isArray": false,
"type": "ID",
"isRequired": true,
"attributes": []
},
"startDate": {
"name": "startDate",
"isArray": false,
"type": "AWSDate",
"isRequired": true,
"attributes": []
},
"endDate": {
"name": "endDate",
"isArray": false,
"type": "AWSDate",
"isRequired": false,
"attributes": []
},
"rate": {
"name": "rate",
"isArray": false,
"type": "Float",
"isRequired": true,
"attributes": []
},
"object": {
"name": "object",
"isArray": false,
"type": "AWSJSON",
"isRequired": false,
"attributes": []
},
"timeline": {
"name": "timeline",
"isArray": false,
"type": {
"model": "Timeline"
},
"isRequired": true,
"attributes": [],
"association": {
"connectionType": "BELONGS_TO",
"targetName": "incomeTimelineId"
}
}
}
},
"UserData": {
"syncable": true,
"name": "UserData",
"pluralName": "UserData",
"attributes": [
{
"type": "model",
"properties": {}
},
{
"type": "searchable",
"properties": {}
},
{
"type": "auth",
"properties": {
"rules": [
{
"groupClaim": "cognito:groups",
"provider": "userPools",
"allow": "groups",
"groups": [
"SuperUser"
],
"operations": [
"create",
"update",
"delete"
]
},
{
"provider": "userPools",
"ownerField": "owner",
"allow": "owner",
"identityClaim": "cognito:username",
"operations": [
"create",
"update",
"delete"
]
}
]
}
}
],
"fields": {
"id": {
"name": "id",
"isArray": false,
"type": "ID",
"isRequired": true,
"attributes": []
},
"birthdate": {
"name": "birthdate",
"isArray": false,
"type": "AWSDate",
"isRequired": true,
"attributes": []
},
"retirementdate": {
"name": "retirementdate",
"isArray": false,
"type": "AWSDate",
"isRequired": true,
"attributes": []
},
"profileImageUrl": {
"name": "profileImageUrl",
"isArray": false,
"type": "string",
"isRequired": false,
"attributes": []
},
"profileImageUncroppedUrl": {
"name": "profileImageUncroppedUrl",
"isArray": false,
"type": "string",
"isRequired": false,
"attributes": []
},
"profileImageManipulations": {
"name": "profileImageManipulations",
"isArray": false,
"type": "AWSJSON",
"isRequired": false,
"attributes": []
}
}
}
},
"enums": {},
"version": "c3d791373597b9b143173b56a57ae474"
};
Not much to add - same as the others. Fix or a workaround would be fantastic as we're in production with no path forward.
@dbhagen @chuckatc @dconlon-monigo @CodySwannGT the fix for the library is already published on @latest tag on npm.
@elorzafe I was getting the same problem as @chuckatc, just updated to @aws-amplify/datastore
version 1.04 and now the sync is not working at all anymore.
I set log level to DEBUG and on 1.0.3. I can see it's doing the sync, but on 1.0.4. there is nothing logged for it.
Do we need to configure the sync?
same here!
@ashteya @mkaschke can you share your package.json and schema.graphql files?
@elorzafe sure!
package.json
{
"name": "cognito-amplify-custom-auth",
"version": "0.0.1",
"description": "TBD",
"main": "index.js",
"repository": "",
"private": true,
"author": "mkaschke",
"license": "ISC",
"scripts": {
"postinstall": "cp -R node_modules/semantic-ui-css/semantic.min.css node_modules/semantic-ui-css/themes style",
"start": "node ./node_modules/webpack-dev-server/bin/webpack-dev-server.js",
"test": "mocha --compilers js:babel-core/register --require ./test/test_helper.js --recursive ./test",
"test:watch": "npm run test -- --watch",
"build": "webpack --progress -p"
},
"devDependencies": {
"@babel/core": "^7.8.0",
"@babel/plugin-proposal-class-properties": "^7.8.0",
"@babel/plugin-transform-runtime": "^7.8.0",
"@babel/preset-env": "^7.8.2",
"@babel/preset-react": "^7.8.0",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.4",
"chai": "^4.2.0",
"css-loader": "^3.4.2",
"eslint": "^5.9.0",
"eslint-config-standard": "^12.0.0",
"eslint-config-standard-react": "^7.0.2",
"eslint-plugin-import": "^2.20.0",
"eslint-plugin-node": "^8.0.0",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-react": "^7.17.0",
"eslint-plugin-standard": "^4.0.0",
"jsdom": "^13.0.0",
"json-loader": "^0.5.7",
"mocha": "^5.2.0",
"react-dates": "^21.5.1",
"webpack": "^4.41.5",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.10.1"
},
"dependencies": {
"amplify-cli": "^1.0.0",
"aws-amplify": "^1.3.3",
"aws-amplify-react": "^2.6.3",
"aws-sdk": "^2.601.0",
"babel-polyfill": "^6.26.0",
"history": "^4.10.1",
"moment": "^2.24.0",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-addons-test-utils": "^15.6.2",
"react-dom": "^16.12.0",
"react-redux": "^7.1.3",
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0",
"redux": "^4.0.5",
"redux-form": "^8.2.3",
"redux-promise": "^0.6.0",
"redux-thunk": "^2.3.0",
"semantic-ui-css": "^2.4.1",
"semantic-ui-react": "^0.86.0",
"style-loader": "^0.23.1"
}
}
schema.graphql
type vehicle @auth(rules: [{ allow: owner, operations: [read, update] }]) @model @searchable {
id: ID!
location: String
city: String
comment: String
startDate: String
endDate: String
creator: String
}
type Subscription @auth(rules: [{allow: owner}]) @model @searchable {
id: ID!
location: String
city: String
status: String
}
@mkaschke can you rename the type Subscription from annotated schema. That is overwriting the Subscription generated by CLI
@mkaschke you should also add @aws-amplify/datastore
to your package.json
file.
@elorzafe thanks very much for the attention on this.
I'll be able to retry the modified demo with @ latest later next week (currently on the road).
@chuckatc @mkaschke Please feel free to re-open/comment in this thread if you still facing issues
I'm still getting an error if I use a custom ownerField
in @auth
decorator. Basically, with the following GraphQL schema it all works fine - default owner
field:
type User @model @auth(rules: [{ allow: owner }]) {
id: ID!
name: String!
email: AWSEmail!
owner: String # required for subscriptions
}
but when I set the ownerField
to be the id
field:
type User @model @auth(rules: [{ allow: owner, ownerField: "id" }]) {
id: ID!
name: String!
email: AWSEmail!
}
it throws the following exception while DataStore attempts to sync local data to the cloud:
{
"errors":[
{
"path":["createUser"],
"data":null,
"errorType":"Unauthorized",
...
"message":"Not Authorized to access createUser on type User"
}
]
}
From what I can tell, DataStore assigns a random ID to the local model created (not the owner ID as it's supposed to), so when trying to sync it with AppSync will get an error due to the constraint on ownerField. This is how I use DataStore to create a new user:
const init = async () => {
const authenticatedUser = await Auth.currentAuthenticatedUser();
const user = await DataStore.query(User, authenticatedUser.username);
if (!user) {
const { name, email } = authenticatedUser.attributes;
await DataStore.save(new User({ name, email }));
}
};
and this is the version of Amplify DataStore I am using in package.json:
"@aws-amplify/datastore": "^1.0.4",
@alex-vladut you are correct, DataStore generate random ids internally.
Using id
as ownerField
is currently not supported. What is the use case you are trying to accomplish?
Thanks for reply @elorzafe. At the moment I am mostly exploring DataStore in order to understand how it works and if I'll be able to use it in a prod environment. Here I try to implement a simple chat app making use of DataStore, and the specific use case listed there is to create a new User item whenever a user signs up for the first time. The item/entity is required to store some user specific settings as well as to link a user to their chat rooms and messages. Basically I wanted to follow the tutorial provided by Nader Dabit and port it over to Amplify DataStore: https://dev.to/dabit3/building-chatt---a-real-time-multi-user-graphql-chat-app-3jik
@elorzafe , pardon the wait, was stuck on aws-amplify/amplify-cli#3300 . Now unblocked, so will test original project soonishly.
fwiw, this recent DataStore demo from Ed Lima uses @auth(rules: [{ allow: owner }])
the same way so will try that as well.
Please feel free to comment in the thread if auth does not work with DataStore
@alex-vladut is correct. You save my life!!
Hi ! I've been struggling with this issue for a while
"@aws-amplify/datastore": "^2.0.8"
CLI : 4.18.0
type Session
@auth(
rules: [
{
allow: owner
}
]
)
@model {
id: ID!
owner: String
title: String
}
From AWS AppSync RealTime (background operation for DataStore sync)
Validation error of type MissingFieldArgument: Missing field argument owner @ 'onCreateSession'"
I tried many things, custom resolvers... removing the mandatory owner parameter from subscription... but it seems like the other previous issues, that DataStore is not sending the owner field in the subscription
The subscriptions sent by AppSync for DataStore being the following :
"subscription operation {
onCreateSession {
id
owner
title
_version
_lastChangedAt
_deleted
}
}
"
I've read on the Amplify Graph API doc (here) that
You don’t need to pass the user as an argument in the subscription request, since the resolver will instead check the contents of your JWT token. So I also tried manually adding the access token in the header
Amplify.configure(awsconfig); Amplify.configure({ graphql_headers: async () => { const session = await Auth.currentSession(); return { Authorization: session.getAccessToken().getJwtToken() }; } } });
But the error is still there, so I don't really know what to do... Did I miss something somewhere (I digged into all the related issues here, and tried all the workaround without success)
@tomheno The subscription should receive owner as argument, something like:
subscription operation($owner: String!) {
onCreateSession(owner: $owner) {
id
owner
title
_version
_lastChangedAt
_deleted
}
}
How did you generate those codes?
@richardfan1126 Got it from the console, Amplify Logger is logging at DEBUG level, see the following screenshot : There's also the same error with onUpdateSession & onDeleteSession subscriptions, that are run by DataStore in background, those messages occures on app start.
I ran into pretty much the same issue with Sync error subscription failed Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onCreateXXX'
. In the end, I managed to work around it by explicitly specifying the owner field in the schema:
type SecondTestField
@auth(
rules: [
{
allow: owner,
ownerField: "owner"
}
]
)
@model {
id: ID!
title: String!
description: String
owner: String
}
Also during the debugging I realized I forgot to run amplify codegen models
, so that may also be one of the steps leading to this issue.
But I don't think it's the only one. I now have for testing two models, one with explicit owner
and one with implicit owner
and when using the implicit/automatic one, I don't get any errors, but I also don't get subscription functionality. I need to refresh the page each time for new data to load. The implicit model is defined like this:
type TestField
@auth(
rules: [
{
allow: owner
}
]
)
@model {
id: ID!
title: String!
description: String
}
so the only difference is missing explicit owner
field. Yet in code, TestField
doesn't support subscriptions (needs a page reload to display new data) and SecondTestField
works as it should.
AWS libs are as follows:
"@aws-amplify/api": "^3.1.9",
"@aws-amplify/datastore": "^2.0.10",
"@aws-amplify/pubsub": "^3.0.10",
"@aws-amplify/ui-react": "^0.2.5",
"aws-amplify": "^3.0.10",
Hi I am having similar issues.
One @auth rule works:
type Task @model
@auth(rules: [
{ allow: owner, ownerField: "owner" }
]) {
id: ID!
title: String!
owner: String
}
But when I want to add a second auth rule
type Task @model
@auth(rules: [
{ allow: owner, ownerField: "owner" },
{ allow: owner, ownerField: "assignee", operations: [update, read] }
]) {
id: ID!
title: String!
owner: String
assignee: String
}
with the following:
[WARN] 40:44.603 DataStore - Sync error subscription failed Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onUpdateTask'"}]}
And does not sync to cloud, local changes are working though.
"dependencies": {
"@aws-amplify/core": "^3.2.6",
"@aws-amplify/datastore": "^2.0.10",
"@aws-amplify/ui-react": "^0.2.5",
I have the same issue.
Using
"@aws-amplify/api": "^3.1.10",
"@aws-amplify/auth": "^3.2.7",
"@aws-amplify/core": "^3.2.7",
"@aws-amplify/datastore": "^2.1.0",
I have tried the various workarounds found here but it still does not work.
@chuckatc mentioned this post here where it seems to work, but I noticed that the author is using npx amplify-app
to init his project, so he does not add an API with amplify add api
.
I am in the case where I had an API before setting up DataStore, so I used the cli to update my API to use DataStore.
@veproza @tomheno In which case are you? Did you init your project with npx amplify-app
or did you update your existing API tu use DataStore?
I have similar error. Right after authenticate user, I'm trying to perform DataStore.query, and get undefined. But after waiting a few seconds and reload applications query successfully returns data.
We have similar issues, all models are marked with @auth
aws-exports
aws-exports
Most of our configuration are manual.
Tried amplify api update
.
Also tried DataStore.configure(), which give other error DataStore - Sync error subscription failed Subscribe only available for AWS AppSync endpoint
.
I have the same issue.
Using
"@aws-amplify/api": "^3.1.10", "@aws-amplify/auth": "^3.2.7", "@aws-amplify/core": "^3.2.7", "@aws-amplify/datastore": "^2.1.0",
I have tried the various workarounds found here but it still does not work.
@chuckatc mentioned this post here where it seems to work, but I noticed that the author is using
npx amplify-app
to init his project, so he does not add an API withamplify add api
.I am in the case where I had an API before setting up DataStore, so I used the cli to update my API to use DataStore.
@veproza @tomheno In which case are you? Did you init your project with
npx amplify-app
or did you update your existing API tu use DataStore?
I made the test and it has nothing to do with whether you started the project using npx amplify-app
or you updated an existing API.
I still have this issue in my React Native app, I created a new issue as this one is closed.
I have a similar issue with
type Quiz @model @auth( rules: [ { allow: public, provider: iam, operations: [read] } { allow: owner } ] ) { id: ID! title: String! seconds: Int! currentQuestion: String questionOrder: String started: Boolean questionTime: Int view: Int owner: String! }
[WARN] 34:16.791 DataStore - Sync error – "Connection failed: {\"errors\":[{\"message\":\"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onUpdateQuiz'\"}]}"
"@aws-amplify/analytics": "^3.1.15", "@aws-amplify/api": "^3.1.15", "@aws-amplify/auth": "^3.2.12", "@aws-amplify/core": "^3.3.2", "@aws-amplify/datastore": "^2.2.2", "@aws-amplify/interactions": "^3.1.15", "@aws-amplify/predictions": "^3.1.15", "@aws-amplify/storage": "^3.2.5", "@aws-amplify/ui": "^2.0.2", "@aws-amplify/ui-react": "^0.2.8", "@aws-amplify/xr": "^2.1.15", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "array-move": "^2.2.1", "aws-amplify": "^3.0.13", "aws-amplify-react": "^4.1.12",
Same issue here
This don't work
@auth( rules: [ { allow: owner, ownerField: "owner" } { allow: owner, ownerField: "tecs", operations: [read, update] } ] ) {...
But only one rule works perfectly
@auth( rules: [ { allow: owner, ownerField: "owner" } ] ) {
"@aws-amplify/datastore": "^2.2.3", "@aws-amplify/datastore": "^2.0.5",
Hello @alexandprivate is there missing comma in auth array? Please check with comma, if it works let us know.
Hello @alexandprivate is there missing comma in auth array? Please check with comma, if it works let us know.
Hi there, well yes and no, prettier actually removed the comma when I save the doc, so I don't think that's the issue, also the model is generated as expected but simply doesn't work, it keeps showing the missing owner field in subscription operation
Ok guys lets see if we can solve this
Hi I am having similar issues.
One @auth rule works:
type Task @model @auth(rules: [ { allow: owner, ownerField: "owner" } ]) { id: ID! title: String! owner: String }
But when I want to add a second auth rule
type Task @model @auth(rules: [ { allow: owner, ownerField: "owner" }, { allow: owner, ownerField: "assignee", operations: [update, read] } ]) { id: ID! title: String! owner: String assignee: String }
with the following:
[WARN] 40:44.603 DataStore - Sync error subscription failed Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onUpdateTask'"}]}
And does not sync to cloud, local changes are working though.
"dependencies": { "@aws-amplify/core": "^3.2.6", "@aws-amplify/datastore": "^2.0.10", "@aws-amplify/ui-react": "^0.2.5",
Hi there @johanbuys any updates on this from your side?
Hi I am having similar issues. One @auth rule works:
type Task @model @auth(rules: [ { allow: owner, ownerField: "owner" } ]) { id: ID! title: String! owner: String }
But when I want to add a second auth rule
type Task @model @auth(rules: [ { allow: owner, ownerField: "owner" }, { allow: owner, ownerField: "assignee", operations: [update, read] } ]) { id: ID! title: String! owner: String assignee: String }
with the following:
[WARN] 40:44.603 DataStore - Sync error subscription failed Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onUpdateTask'"}]}
And does not sync to cloud, local changes are working though."dependencies": { "@aws-amplify/core": "^3.2.6", "@aws-amplify/datastore": "^2.0.10", "@aws-amplify/ui-react": "^0.2.5",
Hi there @johanbuys any updates on this from your side?
Hi, no not really.
I still have the issue. It looks like, If I change around the 2 rules the error changes to match the first field.
This was core to our use case, I did not want to hack something together to make this work so I haven't looked into this for a while. I am monitoring this thread, but I had to refactor my code, not using Datastore for now.
Hopefully these issues can be fixed I was really eager to use this, but for now it's a showstopper.
Hi I am having similar issues. One @auth rule works:
type Task @model @auth(rules: [ { allow: owner, ownerField: "owner" } ]) { id: ID! title: String! owner: String }
But when I want to add a second auth rule
type Task @model @auth(rules: [ { allow: owner, ownerField: "owner" }, { allow: owner, ownerField: "assignee", operations: [update, read] } ]) { id: ID! title: String! owner: String assignee: String }
with the following:
[WARN] 40:44.603 DataStore - Sync error subscription failed Connection failed: {"errors":[{"message":"Validation error of type MissingFieldArgument: Missing field argument owner @ 'onUpdateTask'"}]}
And does not sync to cloud, local changes are working though."dependencies": { "@aws-amplify/core": "^3.2.6", "@aws-amplify/datastore": "^2.0.10", "@aws-amplify/ui-react": "^0.2.5",
Hi there @johanbuys any updates on this from your side?
Hi, no not really.
I still have the issue. It looks like, If I change around the 2 rules the error changes to match the first field.
This was core to our use case, I did not want to hack something together to make this work so I haven't looked into this for a while. I am monitoring this thread, but I had to refactor my code, not using Datastore for now.
Hopefully these issues can be fixed I was really eager to use this, but for now it's a showstopper.
Oh! Sad to hear it, I would like to keep DataStore but implicates to hacking the request buy user and basically remove the @auth from the affected model, let's hope this could be solved sooner than expected.
@elorzafe any updates on this so far?
Hi everybody, I've been having this issue. I'm noticing that it basically only happens when you limit certain operations. Having only operations: ["read"] for me, was producing errors for "onCreate{model}", "onUpdate{model}", and on "onDelete{model}". When I added "update" and "delete" operations, only the error for "onCreate{model}" appeared.
It seems that the Amplify CLI is generating more than it needs to in subscriptions.graphql and maybe elsewhere. I haven't looked into this more as I just found this out, but it's worth trying if you think it helps! I'll comment again if I can figure out more.
edit: In case you're wondering, my model was set to only have operations: ["read"] overall despite my project needing to track changes in real time. A few of the items also had "update", but apparently the object overall needs to adopt all operations for DataStore to work.
Hi everybody, I've been having this issue. I'm noticing that it basically only happens when you limit certain operations. Having only operations: ["read"] for me, was producing errors for "onCreate{model}", "onUpdate{model}", and on "onDelete{model}". When I added "update" and "delete" operations, only the error for "onCreate{model}" appeared.
It seems that the Amplify CLI is generating more than it needs to in subscriptions.graphql and maybe elsewhere. I haven't looked into this more as I just found this out, but it's worth trying if you think it helps! I'll comment again if I can figure out more.
edit: In case you're wondering, my model was set to only have operations: ["read"] overall despite my project needing to track changes in real time. A few of the items also had "update", but apparently the object overall needs to adopt all operations for DataStore to work.
This is also what I have found. See this https://docs.amplify.aws/cli/graphql-transformer/directives#multiple-authorization-rules
type Draft @model
@auth(rules: [
# Defaults to use the "owner" field.
{ allow: owner },
# Authorize the update mutation and both queries.
{ allow: owner, ownerField: "editors", operations: [update, read] }
]) {
id: ID!
title: String!
content: String
owner: String
editors: [String]
}
And this translates to:
Draft that stores unfinished posts for a blog. You might want to allow the Draft’s owner to create, update, delete, and read Draft objects. However, you might also want the Draft’s editors to be able to update and read Draft objects.
This is the exact use case I was trying to accomplish and it did not work.
@yuth @elorzafe @undefobj Can you re-open this issue? It is still not solved in the last relase!
Reopening cc @sammartinez @manueliglesias @iartemiev
Thanks @undefobj, Im going to transfer this to the Amplify JS Repo so we can dig into it
Thank you so much guys for looking into this again, let us know, so we can update our schemas
@sammartinez Any timeline on this? As @johanbuys states, the docs outlined an example for multiple authorization rules which seems to not be working on DataStore.
The ability to limit certain mutations to an owner, for example delete & update, but still allow other users to subscribe to all changes (create, update, delete), seems like a common use case for a lot of apps.
This is a crucial feature for the React Native app I am working on, which uses DataStore since it needs 100% offline capabilities, and seems to be related to 2 other issues I've opened:
@brene @Ashish-Nanda @undefobj @SwaySway @amhinson @manueliglesias @sammartinez @yuth @iartemiev @elorzafe @UnleashedMind
@auth
directive combinationsLike 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.
Library versions:
These steps were performed with/before each test:
If applicable to schema, the following steps were also performed:
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.
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.
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'"}]}
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'"}]}
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'"}]}
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.
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?
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?
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.
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?
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.
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'"}]}
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"}]}
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.
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.
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!
@manueliglesias Thank you! I appreciate the update.
Hi there @manueliglesias any good news to share so far?
Any ETA on when DataStore will work correctly with @auth directives as this currently doesn't work and security is an integral part of any application
Seems like requiring the owner field in the subscription would break a LOT of really common usecases. For example, if I want to have a chat app, and the Message
type has owner - create
authz, then how do I have other users get subscriptions to when new messages are posted?
Hi there guys, any news on this?
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:App.js updated for auth:
The usual
amplify init
,amplify add auth
(Cognito User Pools),npm run amplify-modelgen
,npm run amplify-push
, possibly other commands in thereSigning up and signing in...
Result
Browser fails to sync records giving the following in the console:
which is followed after ~20 seconds by:
Please note
DataStore.observe(Post).subscribe(...)
call and clicking buttons to trigger aDataStore.query()
instead, so it seems DataStore is trying to set up subscriptions itselfowner
to the call toDataStore.save()
apart from records created in IndexedDB now showingowner
owner
fieldSo, is it necessary to configure DataStore explicitly to use
owner
? e.g. an equivalent toAPI.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)