I am a bit confused about how authentication works using AWS Amplify (Cognito and AppSync bundle).
I have setup my authentication method to Cognito and I designed a datamodel using GraphQL API schema.
It looks almost like this (I skipped some elements has they are not relevant to my question):
type Grower #model
#auth(rules: [
{ allow: owner, ownerField: "admins" },
{ allow: owner, ownerField: "members", operations: [read, update, create]},
{ allow: owner, ownerField: "guests", operations: [read]}
]) {
code: String!
name: String!
admins: [String]
members: [String]
guests: [String]
workers: [Workers] #hasMany
orchards: [Orchard] #hasMany
}
type Orchard #model
#auth(rules: [
{ allow: owner }
]){
name: String!
location: String
grower: Grower! #belongsTo
harvests: [Harvest] #hasMany
visits: [Visit] #hasMany
}
Given this schema, will a user declared in the Grower.admins field be able to access an Orchard and its fields if it belongs to the Grower?
And, the opposite, will a user not declared as a member of this Grower (neither guests, member or admins) be able to see the Orchard?
Basically, I would like to understand if my authentication rules 'propagate' throught nested models.
Any comment about this datastructure is welcomed.
Related
Using AWS AppSync GraphQL, I want to be able to have the #auth ownership of one type of document to be based on another. For example, let's say my schema looked like this:
type Course
#model
#auth(rules: [{ allow: owner, ownerField: "contributors", operations: [read, create, update, delete] }])
{
id: ID!
title: String!
contributors: [String!]!
questions: [Question!]! #hasMany
}
type Question
#model
#auth(rules: [{ allow: private, operations: [read, create] }, { allow: owner, operations: [read, create, update, delete] }])
{
id: ID!
title: String!
owner: String!
course: Course! #belongsTo
}
Notice in the above schema, a Course has many Questions, and a Question belongs to a Course. I want to allow the "contributors" of a Course to also have update/delete access on its child Questions, but in the above schema only the creator of the Question (which is any random signed-in user) will have update/delete access.
Is there a way that the Question type could set it's update/delete #auth access to allow not just the owner of the Question, but also of its parent Course "contributors"?
I have the following schema for an amplify project using GraphQL API:
type SomeItem
#model
#auth(
rules: [
{ allow: owner, operations: [create, delete, update] }
]
){
id: ID!
owner: String
version: Int!
text: String
read: Boolean #auth(rules: [{ allow: owner, operations: [create, delete] }])
createdAt: AWSDateTime
updatedAt: AWSDateTime
}
What I want to be able to do is for only the Owner to create/update/delete every field.
I want to allow anybody to update the read field only. I have tried the above to make the read field less restrictive but it's not working. How can I make one field in the model less restrictive than the other fields? Do I need to set an #auth for each field individually?
I have a graphql model in Amplify as follows:
type Blog #model #auth(rules: [
{ allow: owner },
{ allow: groups, groups: ["admins"] },
{ allow: public, provider: apiKey, operations: [read] }
]){
id: ID!
title: String!
content: String!
author: String
}
I would like all field to have read access via an API key except the 'author' field.It should only be readable by owner and the 'Admin' group.
I have tried all sorts of combinations of top level and field level #auth directives but it doesn't work.
Does anyone knows how to solve this.
Thank you
have you tried using the Field Level Authorization?
type User #model {
id: ID!
username: String
ssn: String #auth(rules: [{ allow: owner, ownerField: "username" }])
}
Update: My mistake, in your question it does say you tried this out.
I am making a Team like database. I want all members of the team to have read access, but ultimately each team member will have different permissions.
I set up my team table like:
type Team
#auth(rules: [{ allow: owner, ownerField: "admins", operations: [create, update, delete] }])
#auth(rules: [{ allow: owner, ownerField: "members", operations: [read, update] }]) {
id: ID!
teamID: ID!
userID: ID!
permissions: UserPermission!
admins: [User!]!
members: [User]
}
I was hoping to have some type of query or function that adds admins or members to the database depending on the current user role. I have a TeamUserConnection table, but I wasn't sure if I should be doing this through that table or the resolver. Any help would be awesome!
I'm trying to figure out how can you protect at field level a one-to-many #connection with #auth against mutations that shouldn't be allowed. (ie: deny a specific user to run a mutation that will end-up inserting posts as another user.)
Starting with the example for protecting a mutation at the field level: https://aws-amplify.github.io/docs/cli/graphql#field-level-authorization
I tried doing something like this:
type User #model #auth(rules: [{ allow: owner, ownerField: "id" }]) {
id: ID!
posts: [Post]
#connection(name: "UserPosts")
#auth(rules: [{ allow: owner, ownerField: "id" }])
}
type Post #model {
title: String!
user: User!
#connection(name: "UserPosts")
#auth(rules: [{ allow: owner, ownerField: "userPostId" }])
}
Then say there already is a user with an id of regular-user-id
Apparently my auth rules don't stop another user, say with id of: malicious-user-id to run this mutation:
mutation {
createPost(input:{
title:"Oh this is BAD!"
postUserId: "regular-user-id"
}) {
title
}
}
Running a simple query to make sure this really happened:
query {
getUser(id:"regular-user-id"){
posts{
items
{
title
}
}
}
}
=>
{
"data": {
"getUser": {
"posts": {
"items": [
{
"title": "Regular User title"
},
{
"title": "Oh this is BAD!"
},
]
}
}
}
}
I tried various ways to figure this one out and couldn't find any documentation about bi-directional field level authentication. I'm fairly new to AppSync so I think I must be not getting something, but then this is such common use-case scenario that I'm really surprised there isn't more documentation about it.
Some help would be really appreciated.
To protect the Mutation.createPost mutation such that only the owner of the Post as designated via the postUserId may access it you add an #auth directive to the Post object definition:
type Post #model #auth(rules: [{ allow: owner, ownerField: "postUserId" }]) {
title: String!
# This will use a field 'postUserId' by default.
user: User!
#connection(name: "UserPosts")
}
With this setup, a mutation:
mutation {
createPost(input:{
title:"Oh this is BAD!"
postUserId: "regular-user-id"
}) {
title
}
}
will fail if the logged in user is not "regular-user-id".
This answer may help fill things in as well https://github.com/aws-amplify/amplify-cli/issues/1507#issuecomment-513042021.
Should the malicious user be able to update the Post title? I know this isn't an exact answer to your question since you're focusing on the relation field, but from trying to understand how to do these kind of things myself, I read a few things about introducing some form of 'everyone' group so you can define auth for user's who aren't owners. Then you could put auth on the entire Post model so only owners can update any field;
type Post
#model
#auth(rules: [
{ allow: owner, ownerField: "userPostId" },
{ allow: groups, groups: ["everyone"], operations: [read] }
]) {
title: String!
user: User!
#connection(name: "UserPosts")
}
I'm super new to amplify (I'm currently evaluating whether to use it for a project I'm starting), so I could be completely wrong here. If you do actually want a semi-open model where just the reference field has auth, I'm not sure how to do that :(