Open
Description
Environment information
System:
OS: Windows 11 10.0.26100
CPU: (24) x64 13th Gen Intel(R) Core(TM) i7-13700KF
Memory: 3.31 GB / 31.84 GB
Binaries:
Node: 22.14.0 - C:\Program Files\nodejs\node.EXE
Yarn: undefined - undefined
npm: 11.2.0 - C:\Program Files\nodejs\npm.CMD
pnpm: 10.7.1 - ~\AppData\Local\pnpm\pnpm.CMD
NPM Packages:
@aws-amplify/ai-constructs: Not Found
@aws-amplify/auth-construct: Not Found
@aws-amplify/backend: 1.16.0
@aws-amplify/backend-ai: Not Found
@aws-amplify/backend-auth: Not Found
@aws-amplify/backend-cli: 1.7.0
@aws-amplify/backend-data: Not Found
@aws-amplify/data-construct: Not Found
@aws-amplify/data-schema: Not Found
@aws-amplify/deployed-backend-client: Not Found
@aws-amplify/form-generator: Not Found
@aws-amplify/model-generator: Not Found
@aws-amplify/platform-core: Not Found
@aws-amplify/plugin-types: Not Found
@aws-amplify/sandbox: Not Found
@aws-amplify/schema-generator: Not Found
@aws-cdk/toolkit-lib: Not Found
aws-amplify: 6.14.3
aws-cdk-lib: 2.192.0
typescript: 5.8.3
No AWS environment variables
No CDK environment variables
Describe the bug
When configuring an Amplify Gen 2 Data resource with a custom Lambda authorizer using lambdaAuthorizationMode
and granting AppSync permission to invoke it via schema.authorization(allow => [allow.resource(authorizerHandler)])
, the necessary IAM Service Role for the AppSync API is not being created or assigned during deployment (ampx sandbox
).
Symptoms:
- After a seemingly successful
ampx sandbox
deployment (no errors reported by the CLI), navigating to the deployed AppSync API settings in the AWS console shows the "Role" field under "API configurations -> Logging" is empty.
- The configured Lambda authorizer function is never invoked when making API calls to operations protected by
allow.custom()
. This is confirmed by the fact that the corresponding CloudWatch Log Group for the authorizer Lambda is never created, even though the Lambda function itself exists and its execution role has the necessarylogs:CreateLogGroup
,logs:CreateLogStream
,logs:PutLogEvents
permissions.
- Consequently, API calls to operations using
allow.custom()
fail with an "Unauthorized" error message directly from AppSync, as the authorization check cannot be performed. - Analysis of the CloudFormation stacks shows that the stack responsible for the Lambda function correctly creates the
AWS::Lambda::Permission
resource allowing AppSync invocation. However, the CloudFormation stack responsible for theAWS::AppSync::GraphQLApi
resource does not contain anAWS::IAM::Role
resource for the AppSync service itself.This suggests Amplify is failing to provision the AppSync service role required for it to assume permissions, including the permission to invoke the configured Lambda authorizer.
Reproduction steps
- Initialize Amplify Backend: Create a basic Amplify Gen 2 project with Auth and Data.
npm create amplify@latest my-app --yes cd my-app
- Define Auth: Configure basic email/password auth in
amplify/auth/resource.ts
.// amplify/auth/resource.ts import { defineAuth } from '@aws-amplify/backend'; export const auth = defineAuth({ loginWith: { email: true, }, });
- Define Minimal Lambda Authorizer: Create a placeholder Lambda function.
amplify/data/my-authorizer/resource.ts
:import { defineFunction } from "@aws-amplify/backend"; export const myAuthorizerHandler = defineFunction({ name: 'my-test-authorizer', entry: './handler.ts', });
amplify/data/my-authorizer/handler.ts
:import type { AppSyncAuthorizerHandler, AppSyncAuthorizerResult } from 'aws-lambda'; export const handler: AppSyncAuthorizerHandler = async (event): Promise<AppSyncAuthorizerResult> => { console.log(`EVENT: ${JSON.stringify(event)}`); // Basic allow for testing invocation return { isAuthorized: true }; };
- Define Data with Lambda Authorizer: Configure
amplify/data/resource.ts
to use the Lambda authorizer.// amplify/data/resource.ts import { a, defineData, type ClientSchema } from '@aws-amplify/backend'; import { myAuthorizerHandler } from './my-authorizer/resource'; // Import the handler const schema = a.schema({ Todo: a.model({ content: a.string(), }) // Use allow.custom() .authorization(allow => [allow.custom()]), // Grant AppSync permission to invoke the Lambda }).authorization((allow) => [ allow.resource(myAuthorizerHandler), ]); export type Schema = ClientSchema<typeof schema>; // Configure the data resource with the Lambda authorizer export const data = defineData({ schema, authorizationModes: { defaultAuthorizationMode: 'userPool', // Use Cognito User Pool as default lambdaAuthorizationMode: { function: myAuthorizerHandler, // Link the function timeToLiveInSeconds: 300, }, }, });
- Define Backend: Ensure
amplify/backend.ts
includesauth
anddata
.// amplify/backend.ts import { defineBackend } from '@aws-amplify/backend'; import { auth } from './auth/resource'; import { data } from './data/resource'; export const backend = defineBackend({ auth, data, });
- Deploy Sandbox: Run
npx ampx sandbox
. Wait for deployment to complete. - Check AppSync Settings: Go to the AWS AppSync console, find the deployed API (
amplifyData
), go to Settings. Observe that the "Role" field under "API configurations" is empty (-
). - Attempt API Call: From a client application authenticated with Cognito, attempt an operation on the
Todo
model (e.g.,client.models.Todo.list()
). - Observe Error: The call will fail with an "Unauthorized" error message from AppSync.
- Check CloudWatch: Go to CloudWatch Logs and look for the log group associated with the
my-test-authorizer
Lambda. Observe that the log group does not exist, indicating the Lambda was never invoked.