Search code examples
springamazon-web-servicesmavenamazon-s3

I'm getting an Error in Spring Framework while trying to upload image to S3. Request Signature doesn't match when i use JWT Bearer Token


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.


Solution

  • 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());
            }
        }
    }
    

    I hope this helps anyone encountering the same issue.