Create signed URLs for Google Cloud Storage with node.js for direct upload from browser
google-cloud-storage, javascript, node.js
Solution
As was pointed out by Philip Roberts, aka @LatentFlip on my github repo containing this case, adding a content-type to the signature took care of it.
https://github.com/HenrikJoreteg/google-cloud-signedurl-test-case/pull/1/commits/84290918e7b82dd8c1f22ffcd2c7cdc06b08d334
Also, it sounds like the Google folks are going to update docs/error to be a bit more helpful: https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1695
Problem
actual testcase code: https://github.com/HenrikJoreteg/google-cloud-signedurl-test-case I'm trying to add ability for my API to return signed URLs for direct upload to Google Cloud Storage from the client. Serverside, I'm using the `gcloud` SDK for this: ``` const gcloud = require('gcloud') const gcs = gcloud.storage({ projectId: 'my project', keyFilename: __dirname + '/path/to/JSON/file.json' }) const bucket = gcs.bucket('bucket-name') bucket.file('IMG_2540.png').getSignedUrl({ action: 'write', expires: Date.now() + 60000 }, (error, signedUrl) => { if (error == null) { console.log(signedUrl) } }) ``` Then in the browser I've got an `<input type='file'/>` that I've selected a file with, then I attempt to post it to the URL generated from my server-side script like this: ``` function upload(blobOrFile, url) { var xhr = new XMLHttpRequest(); xhr.open('PUT', url, true); xhr.onload = function(e) { console.log('DONE!') }; xhr.upload.onprogress = function(e) { if (e.lengthComputable) { console.log((e.loaded / e.total) * 100) } }; xhr.send(blobOrFile); } // grab the `File` object dropped (which incidentally // matches the file name used when generating the signed URL upload($('[name=file]').files[0], 'URL GENERATED FROM SERVER-SIDE SCRIPT HERE'); ``` What happens? Response is: ``` <Error> <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message> <StringToSign>PUT image/png 1476631908 /bucket-name/IMG_2540.png</StringToSign> </Error> ``` I've re-downloaded the JSON key file to make sure it's current and has proper permissions to that bucket and I don't get any errors or anything when generating the signed URL. The clientside code appears to properly initiate an upload (I see progress updates logged out) then I get the 403 error above. Filenames match, content-types seem to match expected values, expiration seems reasonable. The official SDK generated the URL, so it seems like it'd be ok. I'm stuck, any help appreciated.