Guide Spring Boot Cloud Storage

S3 pre-signed URLs in Spring Boot

May 11, 2026 9 min read

Serving private files securely from Amazon S3 requires more than public file URLs. This guide explains how to generate pre-signed URLs in Spring Boot for secure, scalable, and temporary file access.

Access pattern summary

S3 pre-signed URLs allow Spring Boot applications to securely provide temporary file access without exposing S3 buckets publicly or routing downloads through backend servers.

Many applications either expose S3 files publicly or force every file request through the backend server. Both approaches create security, scalability, or performance problems.

Pre-signed URLs solve this by allowing controlled temporary access directly from S3 while keeping authorization inside your backend.

What are S3 pre-signed URLs

A pre-signed URL is a temporary link that allows access to a specific file in S3.

  • generated by your backend
  • valid for a limited time
  • grants controlled access to a file

Why use S3 pre-signed URLs

  • avoid making files publicly accessible
  • reduce load on your backend server
  • provide time-limited access
  • improve scalability

How S3 pre-signed URLs work in Spring Boot

  1. Client requests access to a file
  2. Backend validates JWT and permissions
  3. Server generates temporary pre-signed URL
  4. Client downloads file directly from S3
  5. URL expires automatically after configured duration

Where to generate pre-signed URLs

URL generation should happen in your backend, not on the client.

  • validate user identity first
  • check file ownership or permissions
  • generate URL only if authorized
code
import java.net.URL;
import java.time.Duration;

import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;

GetObjectRequest getObjectRequest = GetObjectRequest.builder()
    .bucket(bucketName)
    .key(objectKey)
    .build();

GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder()
    .signatureDuration(Duration.ofMinutes(15))
    .getObjectRequest(getObjectRequest)
    .build();

PresignedGetObjectRequest presignedRequest =
    s3Presigner.presignGetObject(presignRequest);

URL downloadUrl = presignedRequest.url();

This example creates a short-lived download URL. Keep the bucket private and authorize the current user against the requested object before building the request.

  • The URL expires after 15 minutes; choose the shortest duration that fits the workflow.
  • Create S3Presigner once as a managed Spring bean and close it during application shutdown instead of rebuilding it per request.
  • Use presignGetObject for downloads. Upload flows require a separate PutObjectRequest and presignPutObject call.
  • Return only the resulting URL after authorization; never send AWS credentials to the client.

Keeping authentication, storage, and URL generation separated makes secure file systems easier to maintain.

code
src/
 ├── controller/
 ├── security/
 ├── service/
 ├── storage/
 ├── s3/
 └── config/

Why public S3 file access becomes a security problem

Many applications expose S3 files publicly because it simplifies downloads. This becomes risky when handling private or user-specific content.

  • files become accessible without authentication
  • private content can leak through shared URLs
  • access control becomes difficult to enforce
  • backend authorization logic gets bypassed

Pre-signed URLs solve this by keeping authorization inside your backend while allowing temporary secure access directly from S3.

Controlling access duration

Pre-signed URLs should always have an expiration time.

  • short duration for sensitive files
  • longer duration for public-like content
  • balance between usability and security

Common mistakes to avoid

  • generating URLs without authorization checks
  • using very long expiration times
  • exposing raw S3 paths
  • mixing URL generation with controller logic

When to use S3 pre-signed URLs

  • secure file downloads
  • user-specific file access
  • scalable file serving systems

Without vs with pre-signed URLs

Without pre-signed URLs

  • public file exposure
  • backend handles all downloads
  • higher server load
  • harder scalability

With pre-signed URLs

  • temporary secure access
  • reduced backend load
  • direct S3 downloads
  • better scalability

Verify

Use the smallest safe test that exercises the implementation described above.

  • Generate a pre-signed URL for a private test object only after the application's authorization check succeeds.
  • Use the URL before it expires, then repeat the request after the configured expiry window.

Expected result

  • ✓ The URL grants temporary access to the intended object before expiry.
  • ✓ The same URL no longer grants access after expiry.
  • ✓ The S3 object does not need public bucket access.

Continue learning