
There are several ways to authorize your application to interact with theAWS AppSync GraphQL API. But what if your application has no authentication? This post shows you a best practice for communicating with AWS AppSync for public web sites.
TL;DR - UseCognito Identity Pools withIAM Roles.
I found many comments onGitHub andStack Overflow that deal with this issue. But no solution felt good until I found theGitHub repo fromdabit3.
AWS AppSync supportsAWS_IAM. With theCognito Identity Pool you can associate the IAM policy.
Code, Code and Code
In the following two steps I explain which changes are necessary.
Step 1: Configure AWS AppSync
The first step is to specify the authentication type inaws-exports.js
. Set theauthenticationType
to'AWS_IAM'
.
File:aws-exports.js
exportdefault{graphqlEndpoint:process.env.AWS_APPSYNC_GRAPHQL_ENDPOINT,region:'eu-central-1',authenticationType:'AWS_IAM'}
Update the AppSync configuration by settingcredentials
to() => Auth.currentCredentials()
.
File:index.js
importReactfrom'react'importReactDOMfrom'react-dom'importAuthfrom'@aws-amplify/auth'importAWSAppSyncClientfrom'aws-appsync'import{ApolloProvider}from'@apollo/client'import{Rehydrated}from'aws-appsync-react'importAppfrom'./App'importAppSyncConfigfrom'./aws-exports'constappSyncConfig={url:AppSyncConfig.graphqlEndpoint,region:AppSyncConfig.region,auth:{type:AppSyncConfig.authenticationType,credentials:()=>Auth.currentCredentials()},disableOffline:true// https://github.com/awslabs/aws-mobile-appsync-sdk-js/issues/102}constappSyncOptions={defaultOptions:{watchQuery:{fetchPolicy:'cache-and-network'}}}constclient=newAWSAppSyncClient(appSyncConfig,appSyncOptions)ReactDOM.render(<ApolloProviderclient={client}><Rehydrated><App/></Rehydrated></ApolloProvider>,document.getElementById('app'))
Not so important
The rest of the following code is only for the completeness of the demo application.
File:App.js
importReactfrom'react'import{Query}from'@apollo/client/react/components'importAuthfrom'@aws-amplify/auth'import{LIST_EVENTS}from'./graphql/queries.gql'Auth.configure({region:process.env.AWS_COGNITO_REGION,identityPoolId:process.env.AWS_COGNITO_IDENTITIY_POOL_ID})exportdefault()=>(<><h1>Events</h1><Queryquery={LIST_EVENTS}>{({loading,error,data})=>(data.listEvents.items.map(event=>(<divkey={`event_${event.id}`}><h2>{event.name}</h2><p>{event.date}</p></div>)))}</Query></>)
File:queries.gql
queryLIST_EVENTS{listEvents{items{idnamedate}}}
File:schema.graphql
typeEvent{id:ID!name:String!date:AWSDateTime!}typeModelEventConnection{items:[Event]nextToken:String}typeQuery{listEvents(limit:Int,nextToken:String):ModelEventConnection}schema{query:Query}
Step 2: Setup Cognito Identity Pool
In my example I use theServerless Framework.
First we define the Cognito Identity Pool and setAllowUnauthenticatedIdentities: true
. This enable access for unauthenticated identities.
In the second part I link the role for the Identity Pool. BTW: You can also set an role for authenticated users viaauthenticated
if your application supports authenticated and unauthenticated users.
At the last step, I create the IAM role and the related policy. Add your resources (Query
,Mutation
,Subscription
) to the policy.
File:serverless.yml
## Cognito Identity PoolCognitoIdentityPool:Type:AWS::Cognito::IdentityPoolProperties:IdentityPoolName:${self:service}-${self:provider.stage}-${self:provider.region}-IdentityPoolAllowUnauthenticatedIdentities:true## IAM rolesCognitoIdentityPoolRoles:Type:AWS::Cognito::IdentityPoolRoleAttachmentProperties:IdentityPoolId:Ref:CognitoIdentityPoolRoles:unauthenticated:!GetAttCognitoUnAuthRole.Arn## IAM role used for unauthenticated usersCognitoUnAuthRole:Type:AWS::IAM::RoleProperties:Path:/AssumeRolePolicyDocument:Version:'2012-10-17'Statement:-Effect:'Allow'Principal:Federated:'cognito-identity.amazonaws.com'Action:-'sts:AssumeRoleWithWebIdentity'Condition:StringEquals:'cognito-identity.amazonaws.com:aud':Ref:CognitoIdentityPool'ForAnyValue:StringLike':'cognito-identity.amazonaws.com:amr':unauthenticatedPolicies:-PolicyName:${self:service}-${self:provider.stage}-${self:provider.region}-AppSyncCognitoPolicyPolicyDocument:Version:'2012-10-17'Statement:-Effect:'Allow'Action:-'mobileanalytics:PutEvents'-'cognito-sync:*'-'cognito-identity:*'Resource:'*'-Effect:AllowAction:-appsync:GraphQLResource:!Join['',[!GetAttGraphQlApi.Arn,'/types/Query/fields/listEvents']]
Ready
🏁 Now you have access to AWS AppSync and thelistEvents
query can be executed without authentication.
Top comments(2)

- LocationZürich
- WorkPrincipal Front End Developer
- Joined
I am yet to try your solution but the AWS documentation for this topic is a complete joke. Thank you for posting this and hopefully tomorrow I have some good luck with it as today was slow progress!

- LocationHalifax, NS, Canada
- WorkTeam lead full stack Engineer at DaySmart Software Inc
- Joined
I am currently trying this and my first question is going to be where in the serverless.yml do we insert those values. I think under resources:Resources: but I am not sure yet
For further actions, you may consider blocking this person and/orreporting abuse