Skip to main content

AWS AppSync GraphQL API Does Not Use API Key Authentication

Overview

This check identifies AWS AppSync GraphQL APIs that rely on API key authentication as their default authorization method. API keys are static credentials that can be easily leaked, shared, or compromised. Stronger authentication methods like IAM, Cognito, OIDC, or Lambda authorizers provide better security and accountability.

Risk

Using API key authentication for AppSync creates several security vulnerabilities:

  • Confidentiality: Leaked API keys allow unauthorized users to read all data accessible through the GraphQL API
  • Integrity: Attackers with a compromised key can execute mutations that modify or delete data
  • Accountability: API keys provide no user identity, making it impossible to audit who performed what actions
  • Revocation difficulty: Rotating or revoking API keys affects all users of that key simultaneously

Remediation Steps

Prerequisites

You need access to the AWS Console with permissions to modify AppSync APIs. For CLI methods, you also need the AWS CLI installed and configured.

Setting up AWS CLI

If you do not have the AWS CLI installed:

  1. Download from https://aws.amazon.com/cli/
  2. Run aws configure to set up your credentials
  3. Verify with aws sts get-caller-identity

AWS Console Method

  1. Open the AWS AppSync console
  2. Select the GraphQL API that uses API key authentication
  3. In the left navigation, click Settings
  4. Under Default authorization mode, click Edit
  5. Choose a stronger authorization type:
    • AWS IAM - Best for service-to-service communication
    • Amazon Cognito User Pool - Best for end-user applications
    • OpenID Connect - For federated identity providers
    • AWS Lambda - For custom authorization logic
  6. Configure the required settings for your chosen authorization type
  7. Click Save

Important: After changing the authorization type, update your application code to use the new authentication method. API calls using the old API key will fail.

AWS CLI

List your AppSync APIs to find the API ID:

aws appsync list-graphql-apis \
--region us-east-1 \
--query 'graphqlApis[*].[name,apiId,authenticationType]' \
--output table

Check the current authentication type for a specific API:

aws appsync get-graphql-api \
--api-id <your-api-id> \
--region us-east-1 \
--query 'graphqlApi.authenticationType'

Update the API to use IAM authentication:

aws appsync update-graphql-api \
--api-id <your-api-id> \
--name <your-api-name> \
--authentication-type AWS_IAM \
--region us-east-1

Update to use Cognito User Pool authentication:

aws appsync update-graphql-api \
--api-id <your-api-id> \
--name <your-api-name> \
--authentication-type AMAZON_COGNITO_USER_POOLS \
--user-pool-config userPoolId=<your-user-pool-id>,awsRegion=us-east-1,defaultAction=ALLOW \
--region us-east-1

Replace the placeholder values:

  • <your-api-id> - The AppSync API ID
  • <your-api-name> - The current name of your API
  • <your-user-pool-id> - Your Cognito User Pool ID (for Cognito authentication)
CloudFormation

Use this template to create a new AppSync API with IAM authentication, or update an existing stack:

AWSTemplateFormatVersion: '2010-09-09'
Description: AppSync GraphQL API with IAM authentication

Parameters:
ApiName:
Type: String
Description: Name for the AppSync GraphQL API
Default: MySecureGraphQLApi

Resources:
AppSyncApi:
Type: AWS::AppSync::GraphQLApi
Properties:
Name: !Ref ApiName
AuthenticationType: AWS_IAM
XrayEnabled: true
LogConfig:
CloudWatchLogsRoleArn: !GetAtt AppSyncLogsRole.Arn
FieldLogLevel: ERROR
ExcludeVerboseContent: false

AppSyncLogsRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: appsync.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs

Outputs:
ApiId:
Description: AppSync API ID
Value: !GetAtt AppSyncApi.ApiId
ApiUrl:
Description: AppSync GraphQL Endpoint URL
Value: !GetAtt AppSyncApi.GraphQLUrl

To use Cognito authentication instead, change the AuthenticationType and add the user pool configuration:

  AppSyncApi:
Type: AWS::AppSync::GraphQLApi
Properties:
Name: !Ref ApiName
AuthenticationType: AMAZON_COGNITO_USER_POOLS
UserPoolConfig:
UserPoolId: !Ref YourUserPoolId
AwsRegion: us-east-1
DefaultAction: ALLOW
Terraform
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = "us-east-1"
}

variable "api_name" {
description = "Name for the AppSync GraphQL API"
type = string
default = "MySecureGraphQLApi"
}

resource "aws_appsync_graphql_api" "secure_api" {
name = var.api_name
authentication_type = "AWS_IAM"
xray_enabled = true

log_config {
cloudwatch_logs_role_arn = aws_iam_role.appsync_logs.arn
field_log_level = "ERROR"
exclude_verbose_content = false
}
}

resource "aws_iam_role" "appsync_logs" {
name = "${var.api_name}-appsync-logs-role"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "appsync.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
}

resource "aws_iam_role_policy_attachment" "appsync_logs" {
role = aws_iam_role.appsync_logs.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs"
}

output "api_id" {
description = "AppSync API ID"
value = aws_appsync_graphql_api.secure_api.id
}

output "api_url" {
description = "AppSync GraphQL Endpoint URL"
value = aws_appsync_graphql_api.secure_api.uris["GRAPHQL"]
}

For Cognito authentication, modify the authentication_type and add the user pool configuration:

resource "aws_appsync_graphql_api" "secure_api" {
name = var.api_name
authentication_type = "AMAZON_COGNITO_USER_POOLS"

user_pool_config {
user_pool_id = aws_cognito_user_pool.main.id
aws_region = "us-east-1"
default_action = "ALLOW"
}
}

Verification

After making changes, verify the authentication type has been updated:

  1. In the AWS Console, go to AppSync > select your API > Settings
  2. Confirm the Default authorization mode is no longer set to API_KEY
CLI verification
aws appsync get-graphql-api \
--api-id <your-api-id> \
--region us-east-1 \
--query 'graphqlApi.authenticationType' \
--output text

The output should show AWS_IAM, AMAZON_COGNITO_USER_POOLS, OPENID_CONNECT, or AWS_LAMBDA instead of API_KEY.

Additional Resources

Notes

  • Application updates required: Changing the authentication type is a breaking change. All client applications must be updated to use the new authentication method before or immediately after this change.

  • Multiple authorization modes: AppSync supports multiple authorization modes on a single API. You can add additional authentication providers without removing existing ones during a transition period.

  • If API keys are truly necessary: Some use cases (like public read-only APIs) may require API keys. If you must use them:

    • Set short expiration times (maximum 365 days, but shorter is better)
    • Limit access to read-only operations using schema-level authorization
    • Enable throttling to limit abuse
    • Monitor usage and rotate keys regularly
    • Use additional authorization at the resolver level