Closed bmitioglov closed 2 years ago
Hi @bmitioglov 👋 thanks for raising this issue. First thing I noticed in the code snippet you provided was that Amplify.configure
is being called within useEffect. This is probably not a good idea as we don't want to initialize Amplify every time every time App re-renders from any state changes that might come from above the component hierarchy.
So, I would first just move that outside of the useState, as well as the component. Ideally it would go at the top of the App.js file (or index.js if you're using the React Native CLI instead of Expo), right under the imports.
Next, if you're using two types of authorization modes - in your code Cognito User Pools to enable ownership and an API Key for public access, you're going to want to enable Multi Auth for DataStore. You can do this by editing your Amplfiy.configure
call to this:
import {Amplify, AuthModeStrategyType } from 'aws-amplify';
import awsconfig from './src/aws-exports';
Amplify.configure({
...awsconfig,
DataStore: {
authModeStrategyType: AuthModeStrategyType.MULTI_AUTH
}
})
This authorization issue could be that DataStore is making the call to AppSync with Cognito User Pool credentials rather than the API Key because without multi auth enabled, it will only use the default auth type - which, from your aws-exports, seems to be AMAZON_COGNITO_USER_POOLS
Here's some more information on this: https://docs.amplify.aws/lib/datastore/setup-auth-rules/q/platform/js/#configure-multiple-authorization-types
Hi @chrisbonifacio , thank you so much for your answer! I applied your suggestions and now I see less errors, but they are still there. Another thing I noticed that errors now are related to relations tables from one-to-many, many-to-many connections.
Example:
[WARN] 44:22.891 DataStore - queryError, User is unauthorized to query syncLibraryRoutineLibraryExercises, some items could not be returned.
[WARN] 44:23.78 DataStore - subscriptionError, Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onUpdateExerciseMuscle on type ExerciseMuscle"}]}
My full model from schema.graphql:
type Unit @model @auth(rules: [{allow: public}]) {
id: ID!
name: String
isActive: Boolean
}
type MeasureHistory @model @auth(rules: [{allow: owner}]) {
id: ID!
date: AWSDate
value: String
measureID: ID @index(name: "byMeasure")
}
type Measure @model @auth(rules: [{allow: public}]) {
id: ID!
name: String
measureType: String
MeasureHistories: [MeasureHistory] @hasMany(indexName: "byMeasure", fields: ["id"])
}
type History @model @auth(rules: [{allow: owner}]) {
id: ID!
date: String
weightLb: String
weightKg: String
exerciseID: ID @index(name: "byExercise")
}
type Muscle @model @auth(rules: [{allow: public}]) {
id: ID!
name: String
category: String
image_url: String
exercises: [Exercise] @manyToMany(relationName: "ExerciseMuscle")
}
type Exercise @model @auth(rules: [{allow: owner}]) {
id: ID!
name: String
routines: [Routine] @manyToMany(relationName: "RoutineExercise")
muscles: [Muscle] @manyToMany(relationName: "ExerciseMuscle")
Histories: [History] @hasMany(indexName: "byExercise", fields: ["id"])
}
type Routine @model @auth(rules: [{allow: owner}]) {
id: ID!
name: String
planName: String
Exercises: [Exercise] @manyToMany(relationName: "RoutineExercise")
}
type LibraryRoutine @model @auth(rules: [{allow: public}]) {
id: ID!
name: String
planName: String
LibraryExercises: [LibraryExercise] @manyToMany(relationName: "LibraryRoutineLibraryExercise")
}
type LibraryExercise @model @auth(rules: [{allow: public}]) {
id: ID!
name: String
categoryName: String
libraryroutines: [LibraryRoutine] @manyToMany(relationName: "LibraryRoutineLibraryExercise")
}
No problem! If you're logged in as a Cognito User, or logged in at all actually, you won't be able to access the types that are only set to public access. You'll have to add another auth rule like so:
type LibraryRoutine @model @auth(rules: [{allow: public}, {allow: private, operations: [read]}]) {
id: ID!
name: String
planName: String
LibraryExercises: [LibraryExercise] @manyToMany(relationName: "LibraryRoutineLibraryExercise")
}
You might also want to adjust the public auth rules so that users that are not logged in have restricted access to those records. Without specifying operations, it implies that unauthenticated users can perform all operations (create, read, update, delete) on a record.
The unauthorized error for the onUpdateExerciseMuscle
seems a little unusual though unless you're not the owner of the record that was updated. I'll have to mess around with your schema to see what might going on exactly.
In the meantime, can you specify whether you're seeing these errors while logged in? What's the difference in behavior between an unauthenticated user and an authenticated one?
@chrisbonifacio,
I did as you said, I have added {allow: private, operations: [read]}
to all public entities. So now the behavior is the following:
When I am not logged in and open the app (SignIn screen on the mobile phone is being shown), I see these errors in the log:
[WARN] 02:50.173 DataStore - subscriptionError, AppSync Realtime subscription init error: No current user
[WARN] 02:50.231 DataStore - User is unauthorized to query syncMeasureHistories with auth mode AMAZON_COGNITO_USER_POOLS. No data could be returned.
[WARN] 02:50.233 DataStore - User is unauthorized to query syncHistories with auth mode AMAZON_COGNITO_USER_POOLS. No data could be returned.
[WARN] 02:50.234 DataStore - User is unauthorized to query syncExercises with auth mode AMAZON_COGNITO_USER_POOLS. No data could be returned.
[WARN] 02:50.235 DataStore - User is unauthorized to query syncRoutines with auth mode AMAZON_COGNITO_USER_POOLS. No data could be returned.
[WARN] 02:50.243 DataStore - User is unauthorized to query syncRoutineExercises with auth mode undefined. No data could be returned.
[WARN] 02:50.589 DataStore - User is unauthorized to query syncExerciseMuscles with auth mode undefined. No data could be returned.
[WARN] 02:50.596 DataStore - User is unauthorized to query syncLibraryRoutineLibraryExercises with auth mode undefined. No data could be returned.
After I sign in with my user I see only 3 errors in the logs:
[WARN] 05:33.231 DataStore - subscriptionError, Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onCreateRoutineExercise on type RoutineExercise"}]}
[WARN] 05:33.242 DataStore - subscriptionError, Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onDeleteRoutineExercise on type RoutineExercise"}]}
[WARN] 05:33.249 DataStore - subscriptionError, Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onUpdateRoutineExercise on type RoutineExercise"}]}
And I still see entities created by another user 😞
Could it be related to the default auth type cognito_user_pool that I chose during amplify add api
?
Hi @chrisbonifacio, is there some workaround maybe? because it's blocking me... What if I just remove all the relations between tables? I need to try
Hey, sorry for the late reply. These warnings seem normal because of the default auth type. I'm not at my pc but you can try running amplify update api and setting the default auth type to API_KEY and then add Cognito User Pools as a secondary type. Let me know if that helps with the unauthenticated subscriptions.
One note, you'll notice that some of the warnings are about types that are not in your schema, like RoutineExercise, etc. These are join tables the CLI creates to handle many to many relationships. Here's the doc page for more information and how to link two records and query that relationship.
https://docs.amplify.aws/lib/datastore/relational/q/platform/js/#many-to-many
Hi @chrisbonifacio , thank you for the reply! I updated api to make api_key as a default auth type and user pools as secondary. However I still see the warnings:
[WARN] 06:19.400 DataStore - queryError, User is unauthorized to query syncRoutineExercises, some items could not be returned.
[WARN] 06:19.463 DataStore - subscriptionError, Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onCreateRoutineExercise on type Subscription"}]}
[WARN] 06:19.468 DataStore - subscriptionError, Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onDeleteRoutineExercise on type Subscription"}]}
[WARN] 06:19.484 DataStore - subscriptionError, Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onUpdateRoutineExercise on type Subscription"}]}
But the main problem right now is that I still see Routine
entities that another user created in my app...
I looked at AppSync graphql api query webpage and I logged in under my user pool user and used this query there:
query MyQuery {
listRoutines {
items {
name
id
}
}
}
and after execution I see the correct result, only routines that belongs to my user. Why do you think it doesn't work in the app? Here is my code to list routines from the app:
const routines = await DataStore.query(Routine);
What do you think might be wrong?
I'm not totally sure if the warnings about the join table subscriptions are normal or not, specifically how the auth rules are supposed to be applied to them.
However, I was able to reproduce the behavior where, in the AppSync console the owner
auth rule is respected and only my user's Routines are returned, but using DataStore in my client returns both users' Routines so the auth rule is not being respected there.
I will let the team know and get some feedback because that seems like a bug.
@chrisbonifacio thank you Chris. I'll probably stick with my own good old java api for now
No problem! So it turns out that if you don't clear DataStore explicitly, records will remain in IndexedDB and can include another user's only if the other user also logged in on the same device. So, to keep from seeing your other test users' records, you can call DataStore.clear
before/after signing out.
const signOutAndClearDataStore = async () => {
await signOut();
await DataStore.clear();
};
If records continue to persist, you can also try clearing the Site Data altogether by navigating to the Dev Tools > Application > Storage > Clear Site Data.
This should make sure everything's cleared and no credentials are lingering in localStorage.
Afterwards, the behavior seemed consistent between DataStore and AppSync in my app.
Oh ok, that's good to know thanks! BTW was you able to reproduce the warnings I've seen as well? Is there a way to know if they are expected and don't affect functionality?
@bmitioglov I did get those warnings about the join tables but so far I don't think they affect functionality. They're just to keep track of the many to many relationships.
Since we resolved the original issue here, going to close this one out but if you experience any weird or unexpected behavior involving them, open a new issue so we can track it as a separate issue.
@chrisbonifacio thank you!
This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.
Looking for a help forum? We recommend joining the Amplify Community Discord server *-help
channels or Discussions for those types of questions.
Before opening, please confirm:
JavaScript Framework
React Native
Amplify APIs
DataStore
Amplify Categories
api
Environment information
Describe the bug
I am creating DataStore Amplify API with several entities having owner authorization rule. After starting application I see lots of errors like this:
31:28.602 DataStore - subscriptionError, Connection failed: {"errors":[{"errorType":"Unauthorized","message":"Not Authorized to access onCreateUnit on type Subscription"}]}
I noticed these errors are related to entities with public auth rule. After I sign in with created user I still see entities from another user, that means owner authorization rule is not working by some reason.
Expected behavior
I expect it to load entities which belongs to the owner, without any warnings in the log.
Reproduction steps
amplify init:
amplify add auth:
amplify add api:
Part of my model in
schema.graphql
:Then I did:
Here is how I initialize Amplify in App.js:
My app authentication looks like this:
Code Snippet
Log output
aws-exports.js
Manual configuration
No response
Additional configuration
No response
Mobile Device
iPhone13
Mobile Operating System
No response
Mobile Browser
No response
Mobile Browser Version
No response
Additional information and screenshots
No response