node: v11.2.0
I've been trying to upload image files with base64 to s3 using presignedUrl.
So, Frontend passes base64 to backend and backend sends it to s3 to get presigned url and resend it to the s3 server to upload the file. but it doesn't save it and gives me an error like this
SignatureDoesNotMatch The request signature we calculated does not match the signature you provided. Check your key and signing method.
I've triple checked key and everything.. all the configuration is correct.
I've specified Bucket, accesKey, secretAccessKey, signatureVersion(v4), region, etc and everything.
const getPresignedUrlFromS3 = async (email: string, avatar) => {
const key = `${email}/${uuid()}.jpeg`;
const { AWS_BUCKET: Bucket } = process.env;
const buffer = Buffer.from(avatar.replace(/^data:image\/\w+;base64,/, ""),'base64');
try {
const presignedUrl = await s3.getSignedUrl('putObject', {
Bucket,
Key: key,
ContentEncoding: 'base64',
ContentType: 'image/jpeg',
Body: buffer
});
return {
url: presignedUrl,
key
};
} catch (e) {
console.log(e.message);
return {
success: false
}
}
};
const sendPresignedUrlWithFile = async (url: string, file) => {
try {
const result = await axios.put(url, file, {
headers: {
'Content-Type': 'image/jpeg'
}
});
return result;
}
catch (e) {
console.log(e.message);
throw new Error(e);
}
}
export const signup = async (req: Request, res: Response): Promise<Response> => {
const { displayName, password, email, avatar } = req.body;
const schema = Joi.object().keys({
displayName: validationUtils.isDisplayName,
password: validationUtils.isPassword,
email: validationUtils.isEmail,
});
let hashedPassword: string = null;
const result: any = Joi.validate({ displayName, password, email }, schema);
if (result.error) {
return res.status(400).json({
msg: result.error.details[0].message,
success: false,
})
}
try {
hashedPassword = await bcryptUtils.hash(password);
const userRes = await userRepository.getUserByEmailOrDisplayName({ displayName, email });
/**
* when the user does not exist on our server
*/
if (userRes.success) {
let bucketObject;
if (avatar) {
bucketObject = await getPresignedUrlFromS3(email, avatar);
await sendPresignedUrlWithFile(bucketObject.url, avatar);
}
const result = await userRepository.signup({ displayName, password, hashedPassword, email, avatar: bucketObject ? bucketObject.key : '' })
return res.json({
result,
url: bucketObject.url
});
}
return res.status(400).json(userRes)
} catch (e) {
console.log(e);
return res.status(400).json(e);
}
}
Thank you!
@SeongwoonHong
It looks like you're missing the Content-Encoding header on axios.put.
Since you're setting that header in the signed URL, it's expected when doing the PUT.
@srchase Thank you for your response... but I've tried to add Content-Encoding header on axios.put
but it's still giving me the same error...
const sendPresignedUrlWithFile = async (url: string, file) => {
try {
const result = await axios.put(url, file, {
headers: {
'Content-Type': 'image/jpeg',
'Content-Encoding': 'base64',
// even tried this
// ConentEncoding: 'base64'
}
});
return result;
}
catch (e) {
console.log(e.message);
throw new Error(e);
}
}
thank you
Does removing the body make a difference for you?
const presignedUrl = await s3.getSignedUrl('putObject', {
Bucket,
Key: key,
ContentEncoding: 'base64',
ContentType: 'image/jpeg'
});
@srchase yes! Thank you! without body, it is working.. it is saved on s3 bucket but.. the thing is the image file is broken.. like this!

i've tried multiple images and all of them are broken.. I'm assuming the way i save (or send) base64 is wrong..??
oh I got it fixed..
const sendPresignedUrlWithFile = async (url: string, file) => {
try {
const type = file.split(';')[0].split('/')[1]
const buffer = Buffer.from(file.replace(/^data:image\/\w+;base64,/, ""),'base64');
const result = await axios.put(url, buffer, {
headers: {
'Content-Type': 'image/jpeg',
'Content-Encoding': 'base64'
},
});
return result;
}...
I really appreciate it!
anyone, please tell me how we can solve this issue on react-native?
thank you in advance.
ImagePicker.showImagePicker(options, response => {
if (response.didCancel) {
console.log('User cancelled photo picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
const source = { uri: response.uri };
axios({
method: 'PUT',
url: this.state.fileUploadUrl,
data: response.data,
headers: {
'Content-Type': 'image/jpeg',
'Content-Encoding': 'base64'
}
})
.then((response2) => {
console.log(response2);
})
.catch((error) => {
console.log(error);
});
}
});
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.
Most helpful comment
oh I got it fixed..
I really appreciate it!