AWS S3 Integration in Spring Boot with Pre-Signed URLs

In modern cloud-native applications, file storage is a key requirement. Whether you’re building a media-rich web platform, a document archival system, or simply storing user profile pictures, object storage systems like Amazon S3 offer scalable and reliable solutions.

This blog focuses on AWS S3 integration with Spring Boot, especially when handling secure file transfers using pre-signed URLs. You’ll learn when to use signed URLs, how they differ from regular uploads, and how to implement them cleanly in your application.

Let’s break it down systematically and explore how AWS S3 integration can improve the scalability and performance of your cloud-native applications.

What is Amazon S3?

Amazon S3 (Simple Storage Service) is a scalable, high-durability object storage platform provided by AWS. It allows applications to store and retrieve any amount of data, at any time, from anywhere on the web. As a foundation for AWS S3 integration, S3 offers powerful features ideal for application storage needs:

▪️Unlimited storage

▪️99.999999999% (11 9’s) of durability

▪️Fine-grained access control via IAM

▪️Lifecycle policies, versioning, and encryption

S3 stores files as objects inside buckets, with each object assigned a unique key.

Project Setup: Spring Boot + AWS SDK

To build a secure and scalable setup, let’s create a Spring Boot application with AWS S3 integration.

▪️Java 17+

▪️Spring Boot 3+

▪️AWS Java SDK v1, reliable for S3 tasks

Required Dependencies

In your pom.xml, add:

<!-- Spring Boot Web -->

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- AWS SDK for S3 -->

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

<!-- Lombok (Optional) -->

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

Configuring AWS Credentials

Use application.properties:

aws.region=ap-south-1
aws.accessKey=YOUR_ACCESS_KEY
aws.secretKey=YOUR_SECRET_KEY
aws.s3.bucket=my-app-bucket

aws.s3.expiration.minutes=10

This is critical for enabling AWS S3 integration in your backend securely and programmatically.

Why Pre-Signed URLs?

Normally, file uploads flow like this:

Client → Backend → S3

This can overload your server, especially for large files.

Pre-signed URLs allow a better approach:

Client → S3 (direct) ← signed URL from Backend

The server only signs the request and delegates the actual upload/download to the client. This improves scalability, performance, and cost-efficiency.

Upload Flow Using Pre-Signed URL

▪️Client requests an upload URL The client sends the desired filename and content type to your Spring Boot backend.

▪️Server generates a signed PUT URL Backend creates a pre-signed URL using AWS SDK and returns it.

▪️Client uploads directly to S3 Using Http PUT, the file is uploaded to S3 using the signed URL.

▪️(Optional) Client informs server Post-upload, the client can notify the server of a successful upload.

Download Flow Using Pre-Signed URL

▪️Client requests a download URL Client sends the object key (filename or ID).

▪️Server creates signed GET URL A pre-signed URL with an expiration time is generated.

▪️Client downloads the file Client accesses the file directly from S3 without burdening your server.

This efficient workflow is a key benefit of AWS S3 integration in scalable systems.

Sample Service: Pre-Signed URL Generator

@Service
public class S3Service {
    @Value("${aws.region}") private String region;
    @Value("${aws.accessKey}") private String accessKey;
    @Value("${aws.secretKey}") private String secretKey;
    @Value("${aws.s3.bucket}") private String bucket;
    @Value("${aws.s3.expiration.minutes}") private int expirationMinutes;
    private AmazonS3 s3Client;

    @PostConstruct
    public void init() {
        BasicAWSCredentials creds = new BasicAWSCredentials(accessKey, secretKey);
        this.s3Client = AmazonS3ClientBuilder.standard()
            .withRegion(region)
            .withCredentials(new AWSStaticCredentialsProvider(creds))
            .build();
    }

    public String generateUploadUrl(String fileName) {
        Date expiration = Date.from(Instant.now().plus(Duration.ofMinutes(expirationMinutes)));
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, fileName)
            .withMethod(HttpMethod.PUT)
            .withExpiration(expiration);
        return s3Client.generatePresignedUrl(request).toString();
    }


    public String generateDownloadUrl(String fileName) {
        Date expiration = Date.from(Instant.now().plus(Duration.ofMinutes(expirationMinutes)));
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, fileName)
            .withMethod(HttpMethod.GET)
            .withExpiration(expiration);
        return s3Client.generatePresignedUrl(request).toString();
    }
}

Comparing Pre-Signed vs Normal Uploads

FeatureNormal File UploadPre-Signed URL Upload

Upload Flow

Client → Server → S3

Client → S3 (via URL from Server)

Backend Load

High (server handles file stream)Minimal (URL generation only)

Security

Backend-authenticated

Signed URLs with expiration

Performance

Slower for large files

Faster and direct

Scalability

Bottleneck at server

Highly scalable

Client Complexity

Simple

Needs PUT/GET implementation

Cost Efficiency

More server resources

Optimized storage cost

Advantages of Pre-Signed URLs

▪️Offloads large file handling from backend

▪️Improves performance for clients

▪️Secure and temporary access to files

▪️Ideal for mobile apps and frontend-heavy platforms

Disadvantages

▪️Slightly more complex for frontend developers

▪️Can be abused if URL is leaked (use short expiry times)

▪️Requires careful logging and monitoring

Security Best Practices

▪️Use short-lived expiration (5–10 minutes)

▪️Don’t expose S3 bucket names publicly

▪️Consider object-level encryption if storing sensitive data

▪️Monitor access logs and usage

Real-World Use Cases

▪️User-uploaded profile images in mobile apps

▪️Video uploads in media platforms

▪️Document storage in enterprise CRMs

▪️IoT sensor logs directly streaming to S3

Across industries, AWS S3 integration supports seamless file handling at scale.

coma

Conclusion

Pre-signed URLs with Amazon S3 allow developers to build highly efficient, scalable, and secure file handling workflows. When combined with Spring Boot, this becomes a robust solution suitable for both startups and enterprise-grade systems.

If you’re building a modern web or mobile app, embracing AWS S3 integration with pre-signed URLs is a future-ready approach.

Keep Reading

Join Us for Your 24/7 Clinical Knowledge Partner – The AI Companions Webinar on Thursday, 17th July 2025 at 11:00 AM EDT

Register Now
  • Service
  • Career
  • Let's create something together!

  • We’re looking for the best. Are you in?