Uploading image to S3 using presigned URL fails on Android #425
Description
I have an implementation using RNFetchBlob.fetch
that works flawlessly for iOS but always fails on Android, and I've been banging my head against this wall for a few days now.
I am uploading an image to AWS S3 using a presigned URL. The presigned URL comes from my server and generates new URLs for each request. However, on Android S3 responds with SignatureDoesNotMatch
. I have set permissions in my AndroidManifest.xml
as well as getting 'granted'
back from PermissionsAndroid.request
.
This is a simplified version of my code. I removed event logging etc to make things clearer.
setImage(uploadUrl) {
const options = {mediaType: 'photo', noData: true, maxWidth: 1920, maxHeight: 1920, quality: 0.2};
const setImage = new Promise((resolve, reject) => {
return ImagePicker.launchImageLibrary(options, (response) => resolve(response));
}).then((response) => {
if (response.didCancel) return;
if (response.error) throw new Error(response.error);
const body = 'RNFetchBlob-' + response.uri;
RNFetchBlob.fetch('PUT', uploadUrl, {'Content-Type': ''}, body).then((result) => {
console.log('imagepicker RESPONSE');
console.log(response);
console.log('BODY');
console.log(body);
console.log('UPLOADURL');
console.log(uploadUrl);
console.log('RNFetchBlob RESULT');
console.log(result);
}).catch((error) => console.log(error));
}).catch((error) => console.log(error));
}
On iOS (device and simulator), as mentioned, everything works well.
On Android (simulator, Marshmallow 6.0, api 23), this produces the following output:
imagepicker RESPONSE
{
fileName: "image-874f9bae-d686-4b4e-b89c-a83f3e02b578.jpg",
fileSize: 46513,
height: 1024,
isVertical: true,
originalRotation: 0,
path: "/storage/emulated/0/Android/data/com.client/files/Pictures/image-874f9bae-d686-4b4e-b89c-a83f3e02b578.jpg",
type: "image/jpeg",
uri: "file:///storage/emulated/0/Android/data/com.client/files/Pictures/image-874f9bae-d686-4b4e-b89c-a83f3e02b578.jpg",
width: 683
}
BODY
"RNFetchBlob-file:///storage/emulated/0/Android/data/com.client/files/Pictures/image-874f9bae-d686-4b4e-b89c-a83f3e02b578.jpg"
UPLOADURL
"https://REDACTED-FOR-GITHUB.s3.amazonaws.com/production/asset/2ea438b8-0ba1-4680-b040-5493db3aac26/--unverified?Signature=78gf5edjILenQfttVB8ehSO5pvDvo%3D&x-amz-acl=public-read&Expires=1499637874&AWSAccessKeyId=REDACTED-FOR-GITHUB"
RNFetchBlob RESULT
FetchBlobResponse {data: "<?xml version="1.0" encoding="UTF-8"?>↵<Error><Cod…519/AxHazwJv34A4oQzpAg20k53LEP4=</HostId></Error>", taskId: "q742yws2pngu48hzk5bbjg", type: "utf8", respInfo: Object, info: function…}array: function ()base64: function ()blob: function ()data: "<?xml version="1.0" encoding="UTF-8"?>↵<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>REDACTED-FOR-GITHUB</AWSAccessKeyId><StringToSign>PUT↵↵application/octet-stream↵1499637117↵x-amz-acl:public-read↵/REDACTED-FOR-GITHUB.s3/production/asset/a0245dd0-f72d-4199-9d29-3bb4de45b19d/--unverified</StringToSign><SignatureProvided> 78gf5edjILenQfttVB8ehSO5pvDvo =</SignatureProvided><StringToSignBytes>50 55 54 0a 0a 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6f 63 74 65 74 2d 73 74 72 65 61 6d 0a 31 34 39 39 32 33 37 31 31 37 0a 78 2d 61 6d 7a 2d 61 63 6c 3a 70 75 62 6c 69 63 2d 72 65 61 64 0a 2f 6d 69 6e 75 74 65 73 2d 73 74 6f 72 61 67 65 2f 70 72 6f 64 75 63 74 69 6f 6e 2f 61 73 71 65 74 2f 61 30 32 34 35 64 64 30 2d 66 37 32 64 2d 34 31 39 39 2d 39 64 32 39 2d 33 62 62 34 64 65 31 35 62 31 39 64 2f 2d 2d 75 6e 76 65 72 45 66 69 65 64</StringToSignBytes><RequestId>BC2909B1F6FA5AB2</RequestId><HostId>H/lwKoVq0GCJB74bslVFiwPhHFZRopoUi7Iv6FDsH+N0519/AxHazwJv34A4oQzpAg20k53LEP4=</HostId></Error>"flush: function ()info: function ()json: function ()path: function ()readFile: function (encode)readStream: function (encode)respInfo: Objectsession: function (name)taskId: "q742yws2pngu48hzk5bbjg"text: function ()type: "utf8"__proto__: Object
Keep in mind that it seems unlikely that there is something wrong with the generated URL since it works 100% on iOS and 0% on Android.
Does anyone know what I'm doing wrong here?
Does anyone have a working solution for uploading images from library and camera on Android to S3 using a presigned URL?
Thank you 😌