AWS S3 RequestTimeTooSkewed from browser

Viewed 279

There is this known issue in S3 that if the system for whatever reason has its clock not synched, the upload fails with RequestTimeTooSkewed error.

There are many solutions to when this is triggered by a server (basically fixing the server clock) but what can I do when this is triggered by the browser of my app users?

Even setting correctClockSkew to true doesn't fix it.

AWS.config.update({
  correctClockSkew: true,
  ...
});
1 Answers

Here's a potential solution for JavaScript in the browser to correct client-side clock skew. Your client sends a HEAD request to an S3 bucket (so permissions would be required, or you use a public bucket, and you'd need CORS on the bucket to expose the data header):

correctClockSkew = (Bucket) => {
    const s3 = new AWS.S3();

    // Head the bucket to get a Date response. The 'date' header
    // will need to be exposed in S3 CORS configuration.
    s3.headBucket({ Bucket }, (err, data) => {
        if (err) {
            console.log('headBucket error:', err);
        } else {
            console.log('headBucket data:', JSON.stringify(data));
            console.log('headBucket headers:', JSON.stringify(this.httpResponse.headers));

            if (this.httpResponse.headers.date) {
                const date = Date.parse(this.httpResponse.headers.date);
                console.log('headers date:', date);
                AWS.config.systemClockOffset = new Date() - date;
                console.log('clock offset:', AWS.config.systemClockOffset);
                // Can now safely generate presigned urls
            }
        }
    });
};

This is borrowed from the aws-js-s3-explorer project.

Another option is to wait for the retry event (borrowed from this comment):

AWS.events.on('retry', function (response: any) {
  if (response.error.name === 'RequestTimeTooSkewed') {
    var serverTime = Date.parse(response.httpResponse.headers['date']);
    var timeNow = new Date().getTime();
    AWS.config.systemClockOffset = Math.abs(timeNow - serverTime);
    response.error.retryable = true;
  }
});
Related