Make a signed axios request from lambda to graphql endpoint

0

Hey Guys,

i have this scenario:

I use serverless framework and i use the serverless-appsync plugin. The primary auth is a cognito user pool. The additional auth is IAM.

My funtion in the serverless file looks like this:

  handleDBStreamArtist:
    handler: functions/streams/dynamodbArtist.handler
    environment:
      APP_SYNC_API_URL: !GetAtt GraphQlApi.GraphQLUrl
    events:
      - stream:
          type: dynamodb
          arn: !GetAtt ArtistTable.StreamArn
    iamRoleStatements:
      - Effect: Allow
        Action:
          - appsync:GraphQL
        Resource:
          - !GetAtt GraphQlApi.Arn
          - !Join [ '/', [ !GetAtt GraphQlApi.Arn, 'types', 'Mutation', 'fields', 'updateArtistSub' ] ]

And my lambda code looks like this:

import axios from "axios";
import gql from "graphql-tag";
import { print } from "graphql";
import { dynamoDBToJSObject } from "../../lib/DynamoDB/dynamoDBToJSObject.js";
import { aws4Interceptor } from "aws4-axios";

const interceptor = aws4Interceptor({
  options: {
    region: process.env.AWS_REGION,
    service: "appsync",
  },
});
axios.interceptors.request.use(interceptor);

//create mutation
const publishItem = gql`
  mutation updateArtistSub($id: ID!, $importSuccess: String!) {
    updateArtistSub(input: { id: $id, importSuccess: $importSuccess }) {
      id
      importSuccess
    }
  }
`;

//send mutation to trigger the subscription in appsync, nothing happens in database, just trigger the subscription
const executeMutation = async (id, importSuccess) => {
  console.info("Executing Mutation");
  const mutation = {
    query: print(publishItem),
    variables: {
      id: id,
      importSuccess: importSuccess,
    },
  };

  try {
    console.info("Attempting Axios");

    const config = {
      url: process.env.APP_SYNC_API_URL,
      method: "post",
      headers: {
        "content-type": "application/json",
      },

      data: JSON.stringify(mutation),
    };

    const data = await axios(config);
    console.log(data);
  } catch (error) {
    console.info("Error caught");
    console.log(error);
  }
};

export const handler = async (event, context, callback) => {
  for (let record of event.Records) {
    switch (record.eventName) {
      case "INSERT":
        break;

      case "MODIFY":
        const item = await dynamoDBToJSObject([record.dynamodb.NewImage]);
        let id = item[0].id;
        let importSuccess = item[0].importSuccess;
        await executeMutation(id, importSuccess);
        break;

      case "DELETE":
        console.log("DELETE");
        break;

      default:
        break;
    }
  }
  return { message: `Finished processing ${event.Records.length} records` };
};

But i always get a unauthorized error. Any Ideas?

2 Answers
0
Accepted Answer

Hello,

Thank you for reaching out to us.

I understand you have an AppSync API with primary auth mode as Cognito and additional authorization on IAM. However, while making the API call from the Lambda function using the third party tool, aws4-axios, you are observing Unauthorized error.

To troubleshoot the issue, I have tried replicating the same in my account. Initially, I created an AppSync API with Cognito as primary auth mode and IAM as additional auth mode. Next, I created a Lambda function with similar code as you have shared. Executing the function, I was observing the similar error. I have performed below troubleshooting to move past the issue. I would request you to confirm the following steps and changes:

  1. As the code above is using the AWS Signed requests which is in AppSync terms would be IAM authorization, please confirm if the @aws_iam directive has been added to the schema. This is because IAM auth is the additional authorization on the API. Refer to the document for more information on additional auth modes in AppSync. Furthermore, please confirm the AppSync query is returning the response successfully in the AppSync console with the IAM authorization.
  2. Next, we need to make sure the correct IAM role/credentials are being passed to the aws4Interceptor along with the region and service information. Refer to the third party documentation for more information on passing credentials/IAM role in the aws4Interceptor .
  3. Confirming the above two points, I was still observing the Unauthorized error. Checking the GitHub issues for the tool, I found the issue which was related to the error we are observing. I see that the headers in AppSync API are being passed as the AxiosHeaders which is not being accepted by the API and hence, the error is being observed. Changing the code under node_modules/aws4-axios/dist/interceptor.js to the code mentioned in the above issue, I was able to successfully make the API request to the AppSync API.

I see that this bug is still open. Please note that, as this tool is third party, it is not maintained by AWS. I have performed the above troubleshooting with respect to the tool on my best efforts to assist you. There could be other ways to troubleshoot this error as when the node_modules folder is refreshed, the workaround above would not work and we need to change the code again. Hence, to permanent fix, I would suggest following up on the GitHub issue for the fix of the same.

I hope above troubleshooting help you move past the error while making API request to the AppSync API. In case you require further troubleshooting specific to the resources in your account, feel free to raise a support case with us. We shall be delighted to assist you further.

Have a nice day ahead!

AWS
SUPPORT ENGINEER
answered a year ago
0

Hello,

thank you for the prompt answer. I've made a solution to work with an api-key, that's also fit it.

Best Sascha

answered a year 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.

Guidelines for Answering Questions