I have an AWS AppSync schema with the default authorization mode set to Amazon Cognito User Pool. I make calls to this AppSync endpoint from a web app using AWS Amplify GraphQL Client and, coherently, its configuration points Cognito User Pools as authentication type, too:
aws_appsync_authenticationType: 'AMAZON_COGNITO_USER_POOLS'
It works as expected when the user is authenticated; however (although the involving Cognito Identity Pool has proper Auth and Unath roles set already), when the website runs some Amplify fetch command like for a unauthenticated(guest) user:
const item = await API.graphql(graphqlOperation(getItem, { id: 'my-id' }))
Ends up with throwing an error:
"No current user"
Well, I expected it to perform if I allow unauthenticated users, but it simply fails. Seeking for a way out, I found some discussions like:
And, all of the above suggest revisiting the Amplify configs so that the AppSync authentication type is converted from AMAZON_COGNITO_USER_POOLS
to AWS_IAM
or API_KEY
. However, for some detailed reason 1:
AMAZON_COGNITO_USER_POOLS
authentication type,@aws_auth
decorators or such.Is it possible in any way?
1 I have more granular controls depending on the user's group (admin, normal etc.) with decorators such as @aws_auth(cognito_groups: ["default-user-group"])
on the AppSync schema. So, I need Cognito User Pools for that usage.
So, I just went through a similar issue and managed to get it sorted. I hope this might help you sort this out. The SO question you mentioned in your question is almost the right way to do it. However, there are one "little" tiny details that are not documented and took me a while to find out.
Apart from having to enable both authenticated and unauthenticated access by running amplify update auth
(you can see how in the SO linked above) there are other tweaks you need to do.
First, in your model you need to adjust your rules to be something like:
@auth(
rules: [
# allow owners ability to update and delete their these messages (user pools)
{ allow: owner },
# allow all authenticated users to access this data
{ allow: private, provider: userPools },
# allow all guest users (not authenticated) to access this data
{ allow: public, provider: iam }
]
)
Once you set up this model to allow user pools to access all the data they "own", you can also let any "guest" user to access the data too.
In the frontend, let's get your code as an example, you need to use a bit of a different approach:
Instead of
const item = await API.graphql(graphqlOperation(getItem, { id: 'my-id' }))
try something like
// Check if the user is logged in or not
let isLoggedIn = await isLoggedIn();
const item = (await API.graphql({
query: getItem,
variables: { id: 'my-id' },
authMode: isLoggedIn ? GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS : GRAPHQL_AUTH_MODE.AWS_IAM,
}));
by the way the "isLoggedIn" function look like this
async function isLoggedIn() {
// Another way to get if its a guest or not
//return await Auth.Credentials.getCredSource() === "guest"
try {
await Auth.currentAuthenticatedUser();
return true;
} catch {
return false;
}
}
So... this line is what it does the trick, which is not really well documented.
authMode: isLoggedIn ? GRAPHQL_AUTH_MODE.AMAZON_COGNITO_USER_POOLS : GRAPHQL_AUTH_MODE.AWS_IAM
you need to path the different methods according to the state of the user (logged in or guest), not just the AWS_IAM one.
This will only get you as far as READING the data, in order to make sure guests can do Create/Update/Delete, and separate the data ownership from each other and logged users, that's a completely different story that you will need to start digging up on resolvers to get it sorted. But the good news is, there is a way :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With