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.