AWS Lambda Authorizer returns "BadRequestException"

90 Views Asked by At

I'm using an AWS Lambda to authorize a GraphQL query, I want to use the authorization token to get the client information from Cognito, and use the sub in the user attributes to check if the user purchased a phone in my Record Table, but every time I call the method it returns BadRequestException: Unknown error at buildRestApiServiceError.

Schema:

type Phone
  @model
  @auth(rules: [{ allow: owner }, { allow: custom, operations: [read] }]) {
  id: ID!
  title: String!
  description: AWSJSON!
  rating: Float
}

AWS Lambda:

exports.handler = async (event) => {
  console.log(`EVENT: ${JSON.stringify(event)}`);
  const {
    authorizationToken,
    requestContext: { queryString },
  } = event;

  try {
    const cognitoClient = new CognitoIdentityProviderClient({});
    const cognitoInput = {
      AccessToken: authorizationToken,
    };

    const cognitoCommand = new GetUserCommand(cognitoInput);
    const user = await cognitoClient.send(cognitoCommand);

    const dynamoClient = new DynamoDBClient({});
    const dynamoInput = {
      Key: {
        id: {
          S: user.Username,
        },
      },
      TableName: "RecordTable",
    };

    const dynamoCommand = new GetItemCommand(dynamoInput);
    const response = await dynamoClient.send(dynamoCommand);

    let isPurchased = false;

    for (let index = 0; index < purchasedPhones.length; index++) {
      const phoneID = purchasedPhones[index];

      if (queryString.includes(phoneID)) {
         isPurchased = true;
         break;
       }
     }

    return {
      isAuthorized: isPurchased,
      resolverContext: {
        userid: userId,
        info: user,
        more_info: response,
      },
      ttlOverride: 300,
    };
  } catch (error) {
    return error;
  }
};

GraphQL method:

 const phone = await client.graphql<GraphQLQuery<GetPhoneQuery>>({
        query: getPhone,
        authMode: "lambda",
        authToken: "xxxxxxx...xxx",
        variables: {
          id,
        },
      });

Function Overview:

{
"AWSTemplateFormatVersion": "2010-09-09",
  "Description": "{\"createdOn\":\"Windows\",\"createdBy\":\"Amplify\",\"createdWith\":\"12.10.1\",\"stackType\":\"function-Lambda\",\"metadata\":{}}",
  "Parameters": {
    "CloudWatchRule": {
      "Type": "String",
      "Default": "NONE",
      "Description": " Schedule Expression"
    },
    "deploymentBucketName": {
      "Type": "String"
    },
    "env": {
      "Type": "String"
    },
    "s3Key": {
      "Type": "String"
    }
  },
  "Conditions": {
    "ShouldNotCreateEnvResources": {
      "Fn::Equals": [
        {
          "Ref": "env"
        },
        "NONE"
      ]
    }
  },
  "Resources": {
    "LambdaFunction": {
      "Type": "AWS::Lambda::Function",
      "Metadata": {
        "aws:asset:path": "./src",
        "aws:asset:property": "Code"
      },
      "Properties": {
        "Code": {
          "S3Bucket": {
            "Ref": "deploymentBucketName"
          },
          "S3Key": {
            "Ref": "s3Key"
          }
        },
        "Handler": "index.handler",
        "FunctionName": {
          "Fn::If": [
            "ShouldNotCreateEnvResources",
            "graphQlLambdaAuthorizer364c8848",
            {
              "Fn::Join": [
                "",
                [
                  "graphQlLambdaAuthorizer364c8848",
                  "-",
                  {
                    "Ref": "env"
                  }
                ]
              ]
            }
          ]
        },
        "Environment": {
          "Variables": {
            "ENV": {
              "Ref": "env"
            },
            "REGION": {
              "Ref": "AWS::Region"
            }
          }
        },
        "Role": {
          "Fn::GetAtt": [
            "LambdaExecutionRole",
            "Arn"
          ]
        },
        "Runtime": "nodejs18.x",
        "Layers": [],
        "Timeout": 25
      }
    },
    "LambdaExecutionRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": {
          "Fn::If": [
            "ShouldNotCreateEnvResources",
            "testLambdaRoleb7fb041f",
            {
              "Fn::Join": [
                "",
                [
                  "testLambdaRoleb7fb041f",
                  "-",
                  {
                    "Ref": "env"
                  }
                ]
              ]
            }
          ]
        },
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "lambda.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        }
      }
    },
    "lambdaexecutionpolicy": {
      "DependsOn": [
        "LambdaExecutionRole"
      ],
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "lambda-execution-policy",
        "Roles": [
          {
            "Ref": "LambdaExecutionRole"
          }
        ],
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": "*",
              "Resource": "*"
            }
          ]
        }
      }
    },
    "PermissionForAppSyncToInvokeLambda": {
      "Type": "AWS::Lambda::Permission",
      "Properties": {
        "FunctionName": {
          "Ref": "LambdaFunction"
        },
        "Action": "lambda:InvokeFunction",
        "Principal": "appsync.amazonaws.com"
      }
    }
  },
  "Outputs": {
    "Name": {
      "Value": {
        "Ref": "LambdaFunction"
      }
    },
    "Arn": {
      "Value": {
        "Fn::GetAtt": [
          "LambdaFunction",
          "Arn"
        ]
      }
    },
    "Region": {
      "Value": {
        "Ref": "AWS::Region"
      }
    },
    "LambdaExecutionRole": {
      "Value": {
        "Ref": "LambdaExecutionRole"
      }
    },
    "LambdaExecutionRoleArn": {
      "Value": {
        "Fn::GetAtt": [
          "LambdaExecutionRole",
          "Arn"
        ]
      }
    }
  }
}

I'm not quite sure what I'm missing here.

2

There are 2 best solutions below

5
Ravin Bandara On

i think you have been missing some points. It looks like your trying to implement authorisation logic for a phone model using AWS AppSync and AWS Lambda.

Check the IAM roles and permissions

verify the authorisation token

Debugging and DynamoDB interaction

Error hadndling

GraphQL query execution

i hope this helps ;)

3
AXJ On

That error is usually due to the denied fields in the return object for the lambda authoriser. deniedFields is an array that should contain all the fields, mutations and queries you DON'T permit the user to make. In your case, the lambda authoriser authorised the request but did not allow the specific request you made, I assume because you are not returning a deniedFields array - https://aws.amazon.com/blogs/mobile/appsync-lambda-auth/.

Return an empty deniedFields array for example and it will work. The whole point of the deniedFeilds is to give you fine-grained control over what each user can see.

Also, I would review the Cognito API quotas if you will call Cognito APIs in the lambda authoriser especially if you are only caching the response for 5 minutes.