skip to Main Content

I am getting the below error when I try to upload an image to S3. It says that the signature does not match the signature provided. I am using JWT Tokens as bearer tokens.

com.amazonaws.services.s3.model.AmazonS3Exception: The request signature we calculated does not match the signature you provided. Check your key and signing method. If you start to see this issue after you upgrade the SDK to 1.12.460 or later, it could be because the bucket provided contains ‘/’. See https://github.com/aws/aws-sdk-java/discussions/2976 for more details (Service: Amazon S3; Status Code: 403; Error Code: SignatureDoesNotMatch; Request ID: 4SSPSNRN59QZNYD5; S3 Extended Request ID: 9+4X7GMOZqKIxuaHUBxB09grlgcY7qsxa0y7kGdxnsXBYKDSmGMpjhxlDj/tkOaYIM83npONvWo=; Proxy: null).

This is my amazonconfig file:

@Configuration
public class AmazonConfig {

    @Bean
    public AmazonS3 s3(){
        AWSCredentials awsCredentials = new BasicAWSCredentials(
                "xxx","xxxxx"
        );
        return AmazonS3ClientBuilder
                .standard()
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                .withRegion("eu-central-1")
                .build();
    }
}

I double checked and the key does not contain any /. The region is correct and the name where I defined the bucket is also correct.

public enum XeramedBucket {

    BUCKET("xeramedimages");
    private final String xeramedBucket;

    XeramedBucket(String xeramedBucket){
        this.xeramedBucket = xeramedBucket;
    }
    public String getXeramedBucket() {
        return xeramedBucket;
    }
}

My machine’s clock is also synchronized.
and here is the dependency version:

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk</artifactId>
    <version>1.12.685</version>
</dependency>

I expected the user to upload an image s3 and save the directory to the database.

2

Answers


  1. Chosen as BEST ANSWER

    In my case extracting the bearer token from the Request Body worked. I changed my controller file like this

    @RequestMapping("/api/client-images")
    

    public class ClientImageController {

    private final ClientImageService clientImageService;
    
    @PreAuthorize("hasAnyAuthority('USER','ADMIN')")
    @PostMapping("{clientId}/upload")
    public ResponseEntity<String> uploadClientImage(@RequestParam("file") MultipartFile file,
                                                    @PathVariable("clientId") Long clientId,
                                                    @RequestHeader("Authorization") String authorizationHeader) {
        // Check if the Authorization header contains a Bearer token
        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Bearer token missing");
        }
    
        // Extract the Bearer token
        String bearerToken = authorizationHeader.substring(7); // Remove "Bearer " prefix
    
        // Delegate file saving logic to service layer
        try {
            clientImageService.uploadClientImage(clientId, file, bearerToken);
            String message = String.format("File '%s' uploaded successfully for client ID: %d", file.getOriginalFilename(), clientId);
            return ResponseEntity.ok(message);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Failed to upload file: " + e.getMessage());
        }
    }
    

    }

    Hope this helps anyone encountering the same issue.


  2. The error you’re encountering, SignatureDoesNotMatch, typically occurs due to authentication issues when the calculated signature doesn’t match the one provided. It seems you’ve ruled out some common causes like incorrect keys, bucket names, and clock synchronization.

    However, there’s a possibility that the way you’re constructing the S3 client might be causing issues. AWS SDK for Java versions 1.12.460 and later introduced a change related to handling buckets that contain a ‘/’. The URL encoding of these bucket names might not match the previous behavior, leading to authentication failures.

    Here’s how you can modify your AmazonConfig class to properly configure the S3 client considering this change:

    @Configuration
    public class AmazonConfig {
    
        @Value("${amazon.access.key}")
        private String awsAccessKey;
    
        @Value("${amazon.secret.key}")
        private String awsSecretKey;
    
        @Bean
        public AmazonS3 s3Client() {
            AWSCredentials awsCredentials = new BasicAWSCredentials(awsAccessKey, awsSecretKey);
            return AmazonS3ClientBuilder.standard()
                    .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                    .withRegion(Regions.EU_CENTRAL_1)
                    .build();
        }
    }
    

    Then, make sure you have your access key and secret key configured properly in your application properties or YAML file:

    amazon.access.key=YOUR_ACCESS_KEY
    amazon.secret.key=YOUR_SECRET_KEY
    

    Also, ensure that you have set the appropriate permissions for your S3 bucket for the access key being used, including both read and write permissions.

    If you’re still facing issues after these modifications, double-check the bucket name and ensure that it adheres to the required naming conventions. Additionally, consider checking if there are any special characters or whitespace in the bucket name that might be causing issues.

    If the issue persists, you might need to enable AWS SDK logging to get more detailed information about the requests being sent to S3, which could help in troubleshooting further.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search