Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to upload a file with $.ajax to AWS S3 with a pre-signed url

Upload a file with $.ajax to AWS S3 with a pre-signed url

When you read about how to create and consume a pre-signed url on this guide, everything is really easy. You get your Postman and it works like a charm in the first run.

Then you open your browser, try your usual $.ajax() and send your PUT operation, and you hit the cold iced wall of AWS error message, a simple <Code>SignatureDoesNotMatch</Code> that will steal hours from your productivity.

So here I come to save you and give you a free working example of how to upload a file directly to AWS S3 from your browser. You are wellcome :).

var s3 = new AWS.S3({
accessKeyId: '<YOUR_ACCESS_KEY>',
secretAccessKey: '<YOUR_SECRET_ACCESS_KEY>'
});
var uploadPreSignedUrl = s3.getSignedUrl('putObject', {
Bucket: '<THE_BUCKET_NAME>',
Key: '<THE_UPLOADED_FILENAME>',
ACL: 'authenticated-read',
// This must match with your ajax contentType parameter
ContentType: 'binary/octet-stream'
/* then add all the rest of your parameters to AWS puttObect here */
});
var downloadPreSignedUrl = s3.getSignedUrl('getObject', {
Bucket: '<THE_BUCKET_NAME>',
Key: '<THE_UPLOADED_FILENAME>',
/* set a fixed type, or calculate your mime type from the file extension */
ResponseContentType: 'image/jpeg'
/* and all the rest of your parameters to AWS getObect here */
});
// now you have both urls
console.log( uploadPreSignedUrl, downloadPreSignedUrl );
<form id="theForm" method="POST" enctype="multipart/form-data" >
<input id="theFile" name="file" type="file"/>
<button id="theButton" type="submit">send 1</button>
</form>
After you uploaded the file you can <a href="<YOUR_PRE_SIGNED_DOWNLOAD_URL_HERE>">download it here</a>
<script src="upload.js"></script>
// Remember to include jQuery somewhere.
$(function() {
$('#theForm').on('submit', sendFile);
});
function sendFile(e) {
e.preventDefault();
// get the reference to the actual file in the input
var theFormFile = $('#theFile').get()[0].files[0];
$.ajax({
type: 'PUT',
url: "<YOUR_PRE_SIGNED_UPLOAD_URL_HERE>",
// Content type must much with the parameter you signed your URL with
contentType: 'binary/octet-stream',
// this flag is important, if not set, it will try to send data as a form
processData: false,
// the actual file is sent raw
data: theFormFile
})
.success(function() {
alert('File uploaded');
})
.error(function() {
alert('File NOT uploaded');
console.log( arguments);
});
return false;
});
}
@jhulford

This comment has been minimized.

Copy link

jhulford commented Aug 15, 2016

Thanks for this...most other docs I saw didn't include the part about the Content-Type header needing to be the same in the upload headers and the presign params. While that makes sense, it's not immediately obvious that that's the cause of the SignatureDoesNotMatch errors.

@dudyn5ky1

This comment has been minimized.

Copy link

dudyn5ky1 commented Aug 16, 2016

Add signatureVersion: 'v4' to 01-backend-url-generation.js.

@ishansan38

This comment has been minimized.

Copy link

ishansan38 commented Nov 29, 2016

Hi. I tried this solution. Though it says "File Uploaded", my Bucket is Still Empty. Can you help me solve this ?
I tried the URL with postman, upload works, but not via this

@schermannj

This comment has been minimized.

Copy link

schermannj commented Feb 23, 2017

That was very helpful, you have saved a lot of my time, thanks a lot!

@anshuraj

This comment has been minimized.

Copy link

anshuraj commented Sep 6, 2017

Thanks a lot. This was very helpful.

@marcucio

This comment has been minimized.

Copy link

marcucio commented Sep 27, 2017

thanks, definitely helped!

@prabhat04011998

This comment has been minimized.

Copy link

prabhat04011998 commented Feb 18, 2018

with uploadPresignedurl can i access the bucket or uploaded file.
<Error> <Code>InvalidRequest</Code> <Message> The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256. </Message> <RequestId>##################</RequestId> <HostId> ############################################</HostId> </Error>

this error is showed when i click on the url showed in the console.

@ChrisGrigg

This comment has been minimized.

Copy link

ChrisGrigg commented Feb 26, 2018

Hi, this solution worked well for me until I started testing with lots of different PDF's. Some PDF's fail silently to upload. Any ideas on why this could be? My code's quite similar only difference is I'm generating pre-signed urls on the client.

** EDIT ** I worked out it was failing with files that had an uppercase ".PDF"

@MidnightJava

This comment has been minimized.

Copy link

MidnightJava commented Mar 10, 2018

Thanks for the explanation. In case anyone gets a CORS failure when running this code in a browser rendering a page outside of the aws domain, you have to configure your S3 service to allow CORS requests.
https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/cors.html
This just configures the server to accept the request. You also have to configure the S3 bucket permissions for uploading files.

@Hirra

This comment has been minimized.

Copy link

Hirra commented Sep 7, 2018

Great post..kudos for the processData:false

@phanikumar1210

This comment has been minimized.

Copy link

phanikumar1210 commented Sep 11, 2018

I have an issue with file upload. I am good with uploading it through curl command but not with ajax call any recommendations.

@brydavis

This comment has been minimized.

Copy link

brydavis commented Oct 21, 2018

Got this to work after some finessing... Main issues I ran into were correctly enabling CORS and making sure may backend signature / settings (e.g. mime type, ACL) matched my subsequent PUT request with the file (hence, I kept receiving the SignatureDoesNotMatch error)

@arswaw

This comment has been minimized.

Copy link

arswaw commented Nov 13, 2018

Hey I wanted to let you know @guumaster that this gist really helped me solve a problem internally with uploading .zip files. I was using blobs and the File API, and it turned out that the solution was just to send the file object direct.

Thank you.

@sevenCS7

This comment has been minimized.

Copy link

sevenCS7 commented Apr 10, 2019

Thanks a lot. This was very helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.