Проблема с вычислением AWS signature4 при запросе API Graphql с использованием Javascript

#javascript #node.js #amazon-web-services #graphql #aws-signature

Вопрос:

Я инженер по контролю качества и хочу автоматизировать наши API graphql, которые находятся за пределами шлюзов AWS. Я хочу добиться этого с помощью Javascripts. Проведя исследование, я понял, что нам нужно сгенерировать подпись AWS с помощью ключа доступа AWS и секретного ключа AWS. Я использую aws4 пакет npm для создания подписи AWS и graphql-request в качестве клиента Javascript для graphql. Я пытаюсь запросить наш API graphql, используя URL-адрес appsync. Написанный ниже код с использованием Javascript mocha тестовой платформы при выполнении, который возвращает мне сообщение об ошибке Error: The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.

Я попробовал использовать postman настольный клиент для запроса graphql API с использованием подписи AWS и отлично работает, получите ожидаемый результат! Если я использую вручную то же authentication headers самое из запроса почтальона, он завершается ошибкой при программном выполнении!

Оцените любые идеи или решения, которые помогут решить проблему при запросе API grapl с использованием подписи AWS.

 var assert = require('assert');
var http = require('https');
var aws4 = require('aws4');
const { GraphQLClient, gql } = require("graphql-request");
var crypto = require('crypto')


describe('Array', function () {

    
    var amzDate = getAmzDate(new Date().toISOString());
    // this function converts the generic JS ISO8601 date format to the specific format the AWS API wants
    function getAmzDate(dateStr) {
        var chars = [":", "-"];
        for (var i = 0; i < chars.length; i  ) {
            while (dateStr.indexOf(chars[i]) != -1) {
                dateStr = dateStr.replace(chars[i], "");
            }
        }
        dateStr = dateStr.split(".")[0]   "Z";
        return dateStr;
    }

    describe('GetUser status ()', function () {
        it('should return the status of the User', async function () {
            const query = gql`
              { 
                getUser(userId: "d8a51af2453") {
                  status
                }
              }
              `
            // get the request body hash
            const getHash = crypto.createHash('sha256').update(query).digest('hex')
            console.log(getHash);

            // aws4 will sign an options object as you'd pass to http.request, with an AWS service and region
            var opts = { service: 'appsync', region: 'eu-west-1' }

            // aws4.sign() will sign and modify these options, ready to pass to http.request
            var awsauth = aws4.sign(opts, { accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY })
            var awsAuthHeaders = awsauth.headers.Authorization;
            console.log(awsauth);

            const graphQLClient = new GraphQLClient('https://<uniqueId>.appsync-api.eu-west-1.amazonaws.com/graphql', { headers: { authorization: awsAuthHeaders, 'X-Amz-Date': amzDate, 'X-Amz-Content-Sha256': getHash }, });
            console.log(graphQLClient);

            const data = await graphQLClient.request(query)
            console.log(JSON.stringify(data))

        });


    });
}); 

GraphQLClient пример вывода консоли выглядит следующим образом:

 GraphQLClient {
  url: 'https://<uniqueId>.appsync-api.eu-west-1.amazonaws.com/graphql',
  options: {
    headers: {
      authorization: 'AWS4-HMAC-SHA256 Credential=AKIARASBW/20211005/eu-west-1/appsync/aws4_request, SignedHeaders=host;x-amz-date, Signature=d4a02fe6f6c3be5c5d2f6d6e19e4b32fd88ad0f3a0c',
      'X-Amz-Date': '20211005T133243Z',
      'X-Amz-Content-Sha256': 'f6b32c10d7968ce5b73783b77564d2c8'
    }
  }
}
 

Complete Error Message

 Error: The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.

The Canonical String for this request should have been
'POST
/graphql

host:<uniqueId>.appsync-api.eu-west-1.amazonaws.com
x-amz-date:20211005T133243Z

host;x-amz-date
abbabb07714cac737137d952f0f5eb59807'

The String-to-Sign should have been
'AWS4-HMAC-SHA256
20211005T133243Z
20211005/eu-west-1/appsync/aws4_request
3b8858c0ac56f03c47b6ab08b68445'
: {"response":{"errors":[{"errorType":"BadRequestException","message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.nnThe Canonical String for this request should have beenn'POSTn/graphqlnnhost:<uniqueId>.appsync-api.eu-west-1.amazonaws.comnx-amz-date:20211005T133243Znnhost;x-amz-datenabbabb07714cac737137d952f0f5eb5980e559113979727ce4'nnThe String-to-Sign should have beenn'AWS4-HMAC-SHA256n20211005T133243Zn20211005/eu-west-1/appsync/aws4_requestc70829ce6a36f62b673'n"}],"status":400,"headers":{}},"request":{"query":"n    {n        getUser(userId: "e8213d09-cdfd-94a7-ae07-cd8a51af2453") {n            statusn      }n    }n  "}}
      at node_modules/graphql-request/dist/index.js:254:31
      at step (node_modules/graphql-request/dist/index.js:63:23)
      at Object.next (node_modules/graphql-request/dist/index.js:44:53)
      at fulfilled (node_modules/graphql-request/dist/index.js:35:58)
      at processTicksAndRejections (internal/process/task_queues.js:97:5)
 

References

  1. aws4 signature generation reference from examples listed in https://www.npmjs.com/package/aws4
  2. Graphql Javascript client selection from the list https://graphql.org/code/#javascript
  3. GraphQLCLient from usage section https://www.npmjs.com/package/graphql-request