Skip to content

How to configure to use LambdaAuthorizer for custom VTL resolvers query in Amplify project?

0

I am using Amplify JS Gen.1 v6 API (Transformer v2) and Amplify CLI Version 14.2.5

Question I am not able to use / trigger Lambda Authorizer Appsync auth flow for my custom query getComponentFiltered(id: ID!, organizationID: String): Component , which is using custom resolvers created with amplify add custom and then selecting CDK option. My custom VTL resolvers are created in backend and present locally in 'amplify\backend\custom\CustomResolvers\ folder along with 'cdk-stack.ts' and *.vtl files

real problem: when i invoke this query (either from client or from appsync web-console with a selection of Lambda Authorizer) i'm getting this error:

{
  "data": {
    "getComponentFiltered": null
  },
  "errors": [
    {
      "path": [
        "getComponentFiltered"
      ],
      "data": null,
      "errorType": "Unauthorized",
      "errorInfo": null,
      "locations": [
        {
          "line": 2,
          "column": 3,
          "sourceName": null
        }
      ],
      "message": "Not Authorized to access getComponentFiltered on type Query"
    }
  ]
}

my appsync has been set-up with Cognito UserPool as a default authorization method, with AWS_LAMBDA as a secondary method.

I tried:

  • adding @aws_lambda @aws_cognito_user_pools directives to my query in schema.graphql, but it leads to the fact that my custom resolvers are not detected anymore, as it seems appsync auto-generates own VTL templates based on these directives.
  • placing custom resolvers in amplify\backend\api\{my_api_name}\resolvers\ but this way datasource wasn't connected to VTL resolver and query fails

My question: is there a way to attach both AWS_LAMBDA and UserPool authentication capabilities to custom query with custom resolvers?

2 Answers
0

I think that you're hitting a problem where the annotations you're adding to make the custom VTL resolvers work with AppSync causes Amplify to take over resolver generation. You can perhaps work around this by:

  1. Keep your custom query in schema.graphql without any auth directives
  2. Use your CDK custom resource to create the resolver with VTL templates
  3. Add an $util.unauthorized() check in your VTL request template to handle auth manually:
## Query.getComponentFiltered.req.vtl

## Allow both Cognito UserPools and Lambda auth
#set($authMode = $ctx.identity)

#if($util.isNullOrEmpty($ctx.identity))
  $util.unauthorized()
#end

## If using Lambda auth, $ctx.identity.resolverContext will be populated
## If using Cognito, $ctx.identity.sub will be populated

#if($util.isNullOrEmpty($ctx.identity.sub) && $util.isNullOrEmpty($ctx.identity.resolverContext))
  $util.unauthorized()
#end

## Your actual resolver logic
{
  "version": "2017-02-28",
  "operation": "GetItem",
  "key": {
    "id": $util.dynamodb.toDynamoDBJson($ctx.args.id)
  }
}
  1. Configure the AppSync API to accept Lambda auth requests by ensuring AWS_LAMBDA is set as an additional auth mode (via amplify update api → select additional auth types → add Lambda)

  2. When calling from the client, specify the auth mode:

import { API } from 'aws-amplify';

// Using Lambda auth
const result = await API.graphql({
  query: getComponentFiltered,
  variables: { id: '123', organizationID: 'org1' },
  authMode: 'AWS_LAMBDA',
  authToken: 'your-lambda-auth-token'
});

// Using Cognito auth (default)
const result = await API.graphql({
  query: getComponentFiltered,
  variables: { id: '123', organizationID: 'org1' },
  authMode: 'AMAZON_COGNITO_USER_POOLS'
});
AWS
answered 2 months ago
0

Hi, thanks for your fast reply. In my case i cannot use authMode: 'AWS_LAMBDA' as I am using Java client to generate graphql query for one of my important use-cases. In my java query i use "Authorization" header and set it either to my custom PAT-token or to "Bearer + {Cognito Acess Token}" depending on auth method a user selects, like this:

DynamicGraphQLClientBuilder clientBuilder = DynamicGraphQLClientBuilder.newBuilder()
                .url(appsyncEndpoint);        
clientBuilder.header("Authorization", accessToken);

I guess the actual problem is not my VTL resolver, but rather the fact that appsync doesn't call my Authorization lambda at all. I can see in CloudWatch logs that my Lambda Authorizer function is not even triggered (no logs produced). It means resolverContext object will be absent and VTL resolver will always fail as unauthorized. VTL template is called after auth step, isn't it?

Question#1 is it a bug or feature that Appsync doesn't use not primary auth methods if these are not explicitly specified in graphql query (as authMode: 'AWS_LAMBDA')?

Question #2 how to simulate amplify js authMode: 'AWS_LAMBDA' in other graphql clients? I deep searched with AI and was advised that appsync seems using 'Bearer' prefix of 'Authorization' header to switch auth mode between userpool and lambda. Is it true?

I spend a few days trying to find the solution. I don't want to change my Appsync API primary auth method to 'AWS_LAMBDA' as 90% of traffic goes from web users authorized via Cognito UserPool. I want to find a way to tell Appsync to use 'AWS_LAMBDA' auth for this specific query. I am currently thinking in the direction of creation an override logic in cdk-stacks.ts file to force appsync to use specific auth modes for specific queries without any graphql.schema directive, like this:

import { Resolver, AuthorizationType } from 'aws-cdk-lib/aws-appsync';

const getComponentFilteredResolver = new Resolver(this, 'GetComponentFilteredResolver', {
  api: graphqlApi,
  typeName: 'Query',
  fieldName: 'getComponentFiltered',
  dataSource: componentTableDataSource,
  requestMappingTemplate: MappingTemplate.fromFile(
    path.join(__dirname, 'Query.getComponentFiltered.req.vtl')
  ),
  // Primary authorization (Lambda)
  authorizationConfig: {
    authorizationType: AuthorizationType.AWS_LAMBDA,
    lambdaAuthorizerConfig: {
      handler: Function.fromFunctionArn(this, 'LambdaAuth', lambdaAuthorizerArn),
      resultsCacheTtl: cdk.Duration.minutes(5)
    }
  },
  // Additional authorization modes
  additionalAuthorizationModes: [
    {
      authorizationType: AuthorizationType.USER_POOL,
      userPoolConfig: {
        userPool: userPool,
        defaultAction: UserPoolDefaultAction.ALLOW
      }
    }
  ]
});

Question#3 is it possible to use cdk-stack.ts to override auth mode per method/query and if yes, can you give correct example or documentation link?

answered 2 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.