Soto icon

Soto

Pre-signed URLs for S3

One of the most common questions we get about Soto is "How do I pre-sign a URL for uploading to S3?". This is a common pattern where a server provides a pre-signed URL to a client. A pre-signed URL allows you to grant temporary access to a single file in an S3 bucket to someone who normally does not have access. The URL is signed with your credentials and it gives anyone the ability to upload to that object in S3 while it is still valid. Be careful, to not provide these too freely.

Uploading to S3

Assuming you already have an AWSClient, the following will generate an EventLoopFuture that will be fulfilled with a pre-signed URL for uploading to S3 .

let s3 = S3(client: awsClient, region: .useast1)
let signedURLFuture = try s3.signURL(
    url: URL(string: "https://<my-bucket>.s3.us-east-1.amazonaws.com/<my-object>")!,
    httpMethod: .PUT,
    expires: .minutes(15)
)

Replace <my-bucket> with the name of your S3 bucket and <my-object> with the name of the object you want to upload. In this example I am assuming your bucket is in the us-east-1 region. You should replace this, both in the S3 initialization and the unsigned URL, with the region your bucket exists in.

The function signURL returns an EventLoopFuture<URL> and not a URL because the AWSClient which manages credential acquisition, required to sign your URL, could still be in the process of acquiring those credentials.

Downloading from S3

To generate a URL that downloads a file from S3 all you need to do is replace the .PUT with a .GET.

let s3 = S3(client: awsClient, region: .useast1)
let signedURLFuture = try s3.signURL(
    url: URL(string: "https://<my-bucket>.s3.us-east-1.amazonaws.com/<my-object>")!,
    httpMethod: .GET,
    expires: .minutes(15)
)

Including header values

If you want to include some headers values with the URL you have to include the headers while signing it and the client will be required to include exactly the same headers when they use the URL. The following will provide a URL that uploads an object with content type set to "application/json" and canned ACL set to "public-read".

let signedURLFuture = try s3.signURL(
    url: URL(string: "https://<my-bucket>.s3.us-east-1.amazonaws.com/<my-object>")!,
    httpMethod: .PUT,
    headers: ["Content-Type": "application/json", "x-amz-acl": "public-read"],
    expires: .minutes(15)
)

You can find a list of possible headers here.