skip to Main Content

I’m trying to do a request to appsync from a node server, using aws4 module.
My keys and iam policy in the user seem correct, but I’m getting this error

{"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.


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

content-type:application/json
host:*****.appsync-api.eu-central-1.amazonaws.com
x-amz-date:20230303T180202Z

content-type;host;x-amz-date
7f0fb133cf00e6ce0efa197c0e1737c04608f5bc1ee1316a56e0ab5929311496'


The String-to-Sign should have been
'AWS4-HMAC-SHA256
20230303T180202Z
20230303/eu-central-1/appsync/aws4_request
201966c7d6de1f6a0d30748e5e4db678a6dd8eae8011cc4d8a3c91a793f0bbb9'
"}]}

I have a user with a policy to access my graphql api, and his keys are stored in process.env AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY

here is the code calling it

  const options = {
    hostname: hostname,
    path: path,
    service: service,
    method: 'POST',
    region: process.env.AWS_REGION,
    timeout: 5000,
    headers: { ...headers, 'Content-Type' : 'application/json' }
  };
  
  return new Promise((resolve, reject) => {
    const req = https.request(aws4.sign(options), (res) => {.....}
.....

2

Answers


  1. Chosen as BEST ANSWER

    Probably a bug or something with aws4, I switched to @aws-sdk/signature-v4 with the same configuration and it works


  2. Omg, this costed me an entire day..

    It seems like somebody messed up a query string normalization. The query params sorting used to work perfectly up until a couple of days ago. Now it requires a bit of work.

    [AWS EXPECTS THIS QUERY PARAMS]
      ?end=1678313014&query=sum%28increase%28total_deployments_count%7Bdeployment_context%3D%22LOCAL%22%7D%5B1h%3A%5D%29%29%2Bby%2B%28entity_type%29&start=1675733014&step=3600
    [STANDARD QUERY PARAMS]
      ?query=sum%28increase%28total_deployments_count%7Bdeployment_context%3D%22LOCAL%22%7D%5B1h%3A%5D%29%29+by+%28entity_type%29&start=1675733014&end=1678313014&step=3600
    

    Hopefully, I was using the aws-provided libraries to do everything on my end. The solution is also part of their library:

    import { parseQueryString } from "@aws-sdk/querystring-parser"
    import { buildQueryString } from "@aws-sdk/querystring-builder"
    
    function fixedAwsRequest(url: URL, request) {
      // it is now important to sort and serialize the queryparams as AWS expects them
      const parsedQueryString = parseQueryString(url.search)
      const newQueryString = buildQueryString(request.query)
    
      url.search = newQueryString ? ("?" + newQueryString) : ""
    
      return performSignedFetch(url.toString(), request)
    }
    

    Edit: Or it can be the %2B vs +

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search