mhart / aws4

Signs and prepares Node.js requests using AWS Signature Version 4
MIT License
700 stars 175 forks source link

Signature expired... #118

Closed kimfucious closed 3 years ago

kimfucious commented 3 years ago

I'm doing something wrong, obviously...

I have Googled the πŸ’© out of this and keep coming back to the two issues that are closed on this repo.

My scenario is that I've created a lambda that I've scheduled through Amazon Event Bridge to perform a RESTful request upon another function that is setup on an API Gateway with IAM permissions.

This all works initially, but then, after 5 mins (like the other issues I've found) I start to get the following error:

message: 'Signature expired: 20201027T123008Z is now earlier than 20201027T125507Z (20201027T130007Z - 5 min.)'

I, frankly, don't know what I'm doing wrong here, so any advice would be appreciated. The below is my function code, trying to implement all the tricks I've seen to get this not to throw a 403, but to no avail.

const AWS = require("aws-sdk");
const aws4 = require("aws4");
const axios = require("axios");
const apiId = process.env.API_SLUGBUCKETAPI_APIID;
const env = process.env.ENV;
const region = process.env.REGION;
const omit = require("lodash.omit");
const cloneDeep = require("lodash.clonedeep");

AWS.config.update({
  region,
  credentials: new AWS.Credentials(
    process.env.AWS_ACCESS_KEY_ID,
    process.env.AWS_SECRET_ACCESS_KEY,
    process.env.AWS_SESSION_TOKEN
  )
});

const request = {
  host: `${apiId}.execute-api.us-west-2.amazonaws.com`,
  method: "GET",
  url: `https://${apiId}.execute-api.us-west-2.amazonaws.com/${env}/slugify-users`,
  path: `/${env}/slugify-users`,
  service: "execute-api"
};

const credentials = AWS.config.credentials;

const signedRequest = aws4.sign(request, {
  secretAccessKey: credentials.secretAccessKey,
  accessKeyId: credentials.accessKeyId,
  sessionToken: credentials.sessionToken
});

const newSignedRequest = cloneDeep(signedRequest);
newSignedRequest.headers = omit(newSignedRequest.headers, [
  "Host",
  "Content-Length"
]);

newSignedRequest.headers["Date"] = new Date();

console.log("Signed Request", signedRequest);
console.log("New Signed Request", newSignedRequest);

exports.handler = async (event) => {
  // console.log(event);
  try {
    const { data } = await axios(newSignedRequest);
    console.log("DATA: ", data);
    const response = {
      statusCode: 200,
      body: JSON.stringify({ ...data })
    };
    return response;
  } catch (error) {
    console.warn(
      "AUTO SLURP CALLER FAIL: ",
      error.response ? error.response : error
    );
    const response = {
      statusCode: 500,
      body: JSON.stringify(error)
    };
    return response;
  }
};

Got milk? πŸ₯›

mhart commented 3 years ago

You're doing all your signing outside your handler – which means it only gets done once.

You need to sign the request each time your handler is called

kimfucious commented 3 years ago

@mhart, you're a 🌟 !

I was so fixated on the "fixes" that I didn't see what was right in front of my face!

Thanks a bunch for your helpful response.

papagei-ma commented 2 years ago

Hey @mhart, Do you have any suggestion, how to handle, client system date is wrong. Maybe a firewall is blocking them from synchronise their time.