I am implementing image upload to AWS S3 storage, currently I can’t solve the “SingatureDoesNotMatch” error when uploading using the pre-signed URL.
My frontend call looks like this, I retrieve the pre-signed URL but when I try to use it for upload I get the 403 forbidden.
const uploadImageToS3 = async (file, leagueId) => {
const backendUrl = process.env.REACT_APP_BACKEND_URL || 'http://localhost:8080';
const jwtToken = Cookies.get('jwtToken');
const objectKey = `-event-${file.name}`;
const url = `${backendUrl}/aws/generate-presigned-url?fileName=${objectKey}&contentType=image/jpeg`;
try {
const authOptions = {
method: 'GET',
headers: {
'Authorization': `Bearer ${jwtToken}`,
'Content-Type': 'application/json'
}
};
// Fetch the presigned URL from your backend
const response = await fetchWithAuth(url, authOptions, () => console.log('Logout or handle auth failure'));
if (!response.ok) {
throw new Error('Failed to obtain presigned URL');
}
let presignedUrl = await response.text();
// Use the presigned URL to upload the file to S3
const result = await fetch(presignedUrl, {
method: 'PUT',
headers: {
'Content-Type': "image/jpeg",
},
body: file
});
if (!result.ok) {
throw new Error('Failed to upload image to S3');
}
console.log('Uploaded successfully!');
return objectKey;
} catch (error) {
console.error('Error uploading image to S3:', error);
throw error;
}
};
Backend method (bucket name and credentials are correct):
@GetMapping("/generate-presigned-url")
public ResponseEntity<?> generatePresignedUrl(@RequestParam String fileName, @RequestParam String contentType) {
System.out.println(contentType + " filename: " + fileName);
try {
// Set the expiry time. Adjust based on your needs.
Date expiration = new Date();
long expTimeMillis = Instant.now().toEpochMilli();
expTimeMillis += 1000 * 60 * 5;
expiration.setTime(expTimeMillis);
// Generate the pre-signed URL.
GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest(bucketName, fileName)
.withMethod(HttpMethod.PUT)
.withExpiration(expiration)
.withContentType(contentType);
URL url = amazonS3.generatePresignedUrl(generatePresignedUrlRequest);
return ResponseEntity.ok(url.toString());
} catch (Exception e) {
return ResponseEntity.internalServerError().body("Error generating URL: " + e.getMessage());
}
}