Authenticate AppSync With Cognito: Part 1 — Cognito Identity Pools for Unauthenticated Access

Jake Bazin
5 min readMay 22, 2024

--

Introduction

Many public-facing applications require users to access certain features or data without the need for authentication. However, AWS AppSync, by default, does not support unauthenticated requests.

In this first part of my series on AppSync Authentication with Cognito, we will explore how to enable unauthenticated users to securely access an AppSync API using AWS Cognito Identity Pools. By the end of this post, you’ll understand the architectural approach and implementation steps needed to securely grant access to unauthenticated users.

What are Cognito Identity Pools?

Cognito Identity Pools (also known as federated identities) enable you to create unique identities for your users and authenticate them with a variety of identity providers, which we’ll see in the next section.

They allow both authenticated and unauthenticated users to obtain temporary AWS credentials, which can then be used to access AWS services.

This functionality provides a flexible and scalable way to manage user identities and permissions, ensuring secure and efficient access to your AWS resources.

Supported Identity Providers for Cognito Identity Pools

Cognito Identity Pools offer support for various identity providers, giving you great flexibility in authenticating users from one or multiple sources.

Here are the primary types of identity providers that Cognito Identity Pools support:

  1. Cognito User Pools: AWS Cognito User Pools provide a secure and scalable user directory that can handle user sign-up, sign-in, and access control. When integrated with identity pools, users authenticated via user pools can obtain temporary AWS credentials to access AWS services.

2. Social Identity Providers:

  • Facebook: Allow users to sign in with their Facebook accounts.
  • Google: Enable users to authenticate using their Google credentials.
  • Amazon: Support login via Amazon accounts.
  • Apple: Integrate with Apple ID for user authentication.

3. OpenID Connect (OIDC) Providers: Connect with any identity provider that supports the OpenID Connect standard. This includes services like Auth0 and Okta, allowing for extensive flexibility and compatibility with various authentication systems.

4. SAML-based Providers: Integrate with SAML-based identity providers commonly used in enterprise environments. This allows users to authenticate using corporate credentials from providers like Microsoft Active Directory Federation Services (ADFS).

Setup your Cognito Identity Pool and IAM role

To allow unauthenticated users to access an AppSync API, we need to provision the required resources. Here’s some how it works with all infrastructure written with the AWS CDK:

Step 1 - Create an Identity Pool

Make sure to specify that it should allow unauthenticated identities. This means users can access certain AWS resources without needing to sign in. You also need to specify an identity provider, in the snippet below I use a Cognito User Pool.

const identityPool = new cognito.CfnIdentityPool(this, 'IdentityPool', {
identityPoolName: `my-identity-pool`,
allowUnauthenticatedIdentities: true, // Allow unauthenticated access
cognitoIdentityProviders: [
{
clientId: guestUserPoolClient.userPoolClientId,
providerName: guestUserPool.userPoolProviderName,
}
]
});

Step 2 - Provision an IAM Role

Within the identity pool configuration, define an IAM role for unauthenticated users. This role includes policies that specify the permissions for these users, such as access to AppSync.

// Policy gives access to all actions on AppSync
const unauthenticatedPolicyDocument = new iam.PolicyDocument({
statements: [new iam.PolicyStatement({
sid: 'AllActions',
actions: ['appsync:GraphQL'],
resources: ['arn:aws:appsync:*:*:apis/*/types/*/fields/*']
})]
});

// Attach policy to new IAM role
const unauthenticatedRole = new iam.Role(this, 'CognitoDefaultUnauthenticatedRole', {
roleName: `cognito-default-unauthenticated-role`,
description: 'IAM Role to be assumed by Cognito for unauthenticated user',
managedPolicies: [unauthenticatedPolicyDocument.toJSON()],
assumedBy: new iam.FederatedPrincipal('cognito-identity.amazonaws.com', {
StringEquals: { 'cognito-identity.amazonaws.com:aud': identityPool.attrId },
'ForAnyValue:StringLike': { 'cognito-identity.amazonaws.com:amr': 'unauthenticated' },
})
});

Step 3 - Attach IAM role to Cognito Identity Pool

The role must be attached to the identity pool so that it knows to use it. You can provision an unauthenticated role and an authenticated role, for now we only need the unauthenticated role, but this gives us flexibility because we can give unauthenticated users different permissions to authenticated users.

// Attach role to Identity Pool
new cognito.CfnIdentityPoolRoleAttachment(this, 'IdentityPoolRoleAttachment', {
identityPoolId: identityPool.attrId,
roles: {
unauthenticated: unauthenticatedRole.roleArn
}
});

If you’d like to add an authenticated role just follow step 2 again to add the desired permissions, change the variable names, and add it to roles section:

// Attach roles to Identity Pool
new cognito.CfnIdentityPoolRoleAttachment(this, 'IdentityPoolRoleAttachment', {
identityPoolId: identityPool.attrId,
roles: {
authenticated: authenticatedRole.roleArn,
unauthenticated: unauthenticatedRole.roleArn
}
});

Setting Up AWS AppSync for Unauthenticated Access

To allow unauthenticated users to access your AppSync API, you need to configure AppSync to work with your Identity Pool. Here’s a concise guide on setting up AWS AppSync for unauthenticated access:

Step 1: Create an AppSync API

When creating the API you need to specify the authorisation type as `AWS_IAM`, using the `authorizationConfig` option.

const api = new appsync.GraphqlApi(this, 'GraphQLAPI', {
name: `my-graphql-api`,
definition: appsync.Definition.fromFile(path.join(__dirname, 'src/api/schema.graphql')),
authorizationConfig: {
defaultAuthorization: {
authorizationType: appsync.AuthorizationType.IAM,
}
},
logConfig: {
fieldLogLevel: appsync.FieldLogLevel.ALL
}
});

// ...add data sources and resolvers below

Step 2: Create an your GraphQL schema

Create a file called `schema.graphql`. The file should be stored at the path specified with the `definition` option in your api configuration above. Here is a basic example of what it might look like:

type Query {
getPosts: [Post!] @aws_iam
}

type Post {
id: String!
title: String!
author: String!
body: String!
}

The `@aws_iam` directive tells AppSync that an IAM role with the correct permissions is required to access the `getPosts` query. You must add this directive to all queries, mutations, and subscriptions that you want unauthenticated users to access.

If IAM is the primary authentication method, this setting cascades down, and you do not need to add it to the returned types. However, if it is an additional authentication method, you will need to specify it on the types, like so:

type Query {
getPosts: [Post!] @aws_iam
}

type Post @aws_iam {
id: String!
title: String!
author: String!
body: String!
}

Conclusion

By following the steps outlined in this post, you can configure AWS Cognito Identity Pools and IAM roles to enable unauthenticated users to securely access your AWS AppSync API. This setup leverages the power of AWS services to provide seamless and secure access to public features and data in your application.

To summarise, we’ve covered:

1. Creating an Identity Pool: Allowing unauthenticated identities and configuring identity providers.
2. Provisioning an IAM Role: Defining permissions and attaching the role to the identity pool.
3. Setting Up AppSync: Configuring the API with IAM authorisation and defining the GraphQL schema to specify access permissions.

In the next part of this series, I will show you how to add authenticated access using Cognito User Pools. We’ll also discuss how to limit permissions through the use of Cognito Groups, allowing for more granular control over what different users can do within your AppSync API.

Stay tuned for more insights on securing your AWS AppSync APIs with Cognito!

--

--