Generating a presigned URL to upload an object - Amazon Simple Storage Service

Generating a presigned URL to upload an object

A presigned URL gives you access to the object identified in the URL, provided that the creator of the presigned URL has permissions to access that object. That is, if you receive a presigned URL to upload an object, you can upload the object only if the creator of the presigned URL has the necessary permissions to upload that object.

All objects and buckets by default are private. The presigned URLs are useful if you want your user/customer to be able to upload a specific object to your bucket, but you don't require them to have AWS security credentials or permissions.

When you create a presigned URL, you must provide your security credentials and then specify a bucket name, an object key, an HTTP method (PUT for uploading objects), and an expiration date and time. The presigned URLs are valid only for the specified duration. That is, you must start the action before the expiration date and time.

If the action consists of multiple steps, such as a multipart upload, all steps must be started before the expiration. Otherwise, you will receive an error when Amazon S3 tries to start a step with an expired URL.

You can use the presigned URL multiple times, up to the expiration date and time.

Access to presigned URLs

Because presigned URLs grant access to your Amazon S3 buckets to whoever has the URL, we recommend that you protect them appropriately. For more information about protecting presigned URLs, see Limiting presigned URL capabilities.

Anyone with valid security credentials can create a presigned URL. However, for you to successfully upload an object, the presigned URL must be created by someone who has permission to perform the operation that the presigned URL is based upon. For more information, see Who can create a presigned URL.

Generating a presigned URL for uploading objects

You can generate a presigned URL programmatically using the AWS SDKs for .NET, Java, Ruby, JavaScript, PHP, and Python.

You can use the AWS SDK to generate a presigned URL that you or anyone that you give the URL to can use to upload an object to Amazon S3. When you use the URL to upload an object, Amazon S3 creates the object in the specified bucket. If an object with the same key that is specified in the presigned URL already exists in the bucket, Amazon S3 replaces the existing object with the uploaded object.

If you're using Microsoft Visual Studio, you can generate a presigned object URL without writing any code by using AWS Explorer in the AWS Toolkit for Visual Studio. Anyone who receives a valid presigned URL can then programmatically upload an object. For more information, see Using Amazon S3 from AWS Explorer in the AWS Toolkit for Visual Studio User Guide.

For instructions on installing AWS Explorer, see Developing with Amazon S3 using the AWS SDKs, and explorers.

The following examples show how to upload objects using presigned URLs.

The following code examples show how to create a presigned URL for Amazon S3 and upload an object.

Go
SDK for Go V2

// Get a presigned URL for the object. // In order to get a presigned URL for an object, you must // create a Presignclient fmt.Println("Create Presign client") presignClient := s3.NewPresignClient(&client) presignResult, err := presignClient.PresignGetObject(context.TODO(), &s3.GetObjectInput{ Bucket: aws.String(name), Key: aws.String("path/myfile.jpg"), }) if err != nil { panic("Couldn't get presigned URL for GetObject") } fmt.Printf("Presigned URL For object: %s\n", presignResult.URL)
  • Find instructions and more code on GitHub.

Java
SDK for Java 2.x

public static void signBucket(S3Presigner presigner, String bucketName, String keyName) { try { PutObjectRequest objectRequest = PutObjectRequest.builder() .bucket(bucketName) .key(keyName) .contentType("text/plain") .build(); PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder() .signatureDuration(Duration.ofMinutes(10)) .putObjectRequest(objectRequest) .build(); PresignedPutObjectRequest presignedRequest = presigner.presignPutObject(presignRequest); String myURL = presignedRequest.url().toString(); System.out.println("Presigned URL to upload a file to: " +myURL); System.out.println("Which HTTP method needs to be used when uploading a file: " + presignedRequest.httpRequest().method()); // Upload content to the Amazon S3 bucket by using this URL. URL url = presignedRequest.url(); // Create the connection and use it to upload the new object by using the presigned URL. HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestProperty("Content-Type","text/plain"); connection.setRequestMethod("PUT"); OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream()); out.write("This text was uploaded as an object by using a presigned URL."); out.close(); connection.getResponseCode(); System.out.println("HTTP response code is " + connection.getResponseCode()); } catch (S3Exception | IOException e) { e.getStackTrace(); } }
  • Find instructions and more code on GitHub.

JavaScript
SDK for JavaScript V3

Create the client.

// Create service client module using ES6 syntax. import { S3Client } from "@aws-sdk/client-s3"; // Set the AWS Region. const REGION = "REGION"; //e.g. "us-east-1" // Create an Amazon S3 service client object. const s3Client = new S3Client({ region: REGION }); export { s3Client };

Create a presigned URL to upload an object to a bucket.

// Import the required AWS SDK clients and commands for Node.js import { CreateBucketCommand, DeleteObjectCommand, PutObjectCommand, DeleteBucketCommand } from "@aws-sdk/client-s3"; import { s3Client } from "./libs/s3Client.js"; // Helper function that creates an Amazon S3 service client module. import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import fetch from "node-fetch"; // Set parameters // Create a random name for the Amazon Simple Storage Service (Amazon S3) bucket and key export const bucketParams = { Bucket: `test-bucket-${Math.ceil(Math.random() * 10 ** 10)}`, Key: `test-object-${Math.ceil(Math.random() * 10 ** 10)}`, Body: "BODY" }; export const run = async () => { try { // Create an S3 bucket. console.log(`Creating bucket ${bucketParams.Bucket}`); await s3Client.send(new CreateBucketCommand({ Bucket: bucketParams.Bucket })); console.log(`Waiting for "${bucketParams.Bucket}" bucket creation...`); } catch (err) { console.log("Error creating bucket", err); } try { // Create a command to put the object in the S3 bucket. const command = new PutObjectCommand(bucketParams); // Create the presigned URL. const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600, }); console.log( `\nPutting "${bucketParams.Key}" using signedUrl with body "${bucketParams.Body}" in v3` ); console.log(signedUrl); const response = await fetch(signedUrl, {method: 'PUT', body: bucketParams.Body}); console.log( `\nResponse returned by signed URL: ${await response.text()}\n` ); } catch (err) { console.log("Error creating presigned URL", err); } try { // Delete the object. console.log(`\nDeleting object "${bucketParams.Key}"} from bucket`); await s3Client.send( new DeleteObjectCommand({ Bucket: bucketParams.Bucket, Key: bucketParams.Key }) ); } catch (err) { console.log("Error deleting object", err); } try { // Delete the S3 bucket. console.log(`\nDeleting bucket ${bucketParams.Bucket}`); await s3Client.send( new DeleteBucketCommand({ Bucket: bucketParams.Bucket }) ); } catch (err) { console.log("Error deleting bucket", err); } }; run();

Create a presigned URL to download an object from a bucket.

// Import the required AWS SDK clients and commands for Node.js import { CreateBucketCommand, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, DeleteBucketCommand } from "@aws-sdk/client-s3"; import { s3Client } from "./libs/s3Client.js"; // Helper function that creates an Amazon S3 service client module. import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; const fetch = require("node-fetch"); // Set parameters // Create a random names for the S3 bucket and key. export const bucketParams = { Bucket: `test-bucket-${Math.ceil(Math.random() * 10 ** 10)}`, Key: `test-object-${Math.ceil(Math.random() * 10 ** 10)}`, Body: "BODY" }; export const run = async () => { // Create an S3 bucket. try { console.log(`Creating bucket ${bucketParams.Bucket}`); const data = await s3Client.send( new CreateBucketCommand({ Bucket: bucketParams.Bucket }) ); return data; // For unit tests. console.log(`Waiting for "${bucketParams.Bucket}" bucket creation...\n`); } catch (err) { console.log("Error creating bucket", err); } // Put the object in the S3 bucket. try { console.log(`Putting object "${bucketParams.Key}" in bucket`); const data = await s3Client.send( new PutObjectCommand({ Bucket: bucketParams.Bucket, Key: bucketParams.Key, Body: bucketParams.Body, }) ); return data; // For unit tests. } catch (err) { console.log("Error putting object", err); } // Create a presigned URL. try { // Create the command. const command = new GetObjectCommand(bucketParams); // Create the presigned URL. const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600, }); console.log( `\nGetting "${bucketParams.Key}" using signedUrl with body "${bucketParams.Body}" in v3` ); console.log(signedUrl); const response = await fetch(signedUrl); console.log( `\nResponse returned by signed URL: ${await response.text()}\n` ); } catch (err) { console.log("Error creating presigned URL", err); } // Delete the object. try { console.log(`\nDeleting object "${bucketParams.Key}"} from bucket`); const data = await s3Client.send( new DeleteObjectCommand({ Bucket: bucketParams.Bucket, Key: bucketParams.Key }) ); return data; // For unit tests. } catch (err) { console.log("Error deleting object", err); } // Delete the S3 bucket. try { console.log(`\nDeleting bucket ${bucketParams.Bucket}`); const data = await s3Client.send( new DeleteBucketCommand({ Bucket: bucketParams.Bucket, Key: bucketParams.Key }) ); return data; // For unit tests. } catch (err) { console.log("Error deleting object", err); } }; run();
Python
SDK for Python (Boto3)

Generate a presigned URL that can perform an Amazon S3 action for a limited time. Use the Requests package to make a request with the URL.

import argparse import logging import boto3 from botocore.exceptions import ClientError import requests logger = logging.getLogger(__name__) def generate_presigned_url(s3_client, client_method, method_parameters, expires_in): """ Generate a presigned Amazon S3 URL that can be used to perform an action. :param s3_client: A Boto3 Amazon S3 client. :param client_method: The name of the client method that the URL performs. :param method_parameters: The parameters of the specified client method. :param expires_in: The number of seconds the presigned URL is valid for. :return: The presigned URL. """ try: url = s3_client.generate_presigned_url( ClientMethod=client_method, Params=method_parameters, ExpiresIn=expires_in ) logger.info("Got presigned URL: %s", url) except ClientError: logger.exception( "Couldn't get a presigned URL for client method '%s'.", client_method) raise return url def usage_demo(): logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') print('-'*88) print("Welcome to the Amazon S3 presigned URL demo.") print('-'*88) parser = argparse.ArgumentParser() parser.add_argument('bucket', help="The name of the bucket.") parser.add_argument( 'key', help="For a GET operation, the key of the object in Amazon S3. For a " "PUT operation, the name of a file to upload.") parser.add_argument( 'action', choices=('get', 'put'), help="The action to perform.") args = parser.parse_args() s3_client = boto3.client('s3') client_action = 'get_object' if args.action == 'get' else 'put_object' url = generate_presigned_url( s3_client, client_action, {'Bucket': args.bucket, 'Key': args.key}, 1000) print("Using the Requests package to send a request to the URL.") response = None if args.action == 'get': response = requests.get(url) elif args.action == 'put': print("Putting data to the URL.") try: with open(args.key, 'r') as object_file: object_text = object_file.read() response = requests.put(url, data=object_text) except FileNotFoundError: print(f"Couldn't find {args.key}. For a PUT operation, the key must be the " f"name of a file that exists on your computer.") if response is not None: print("Got response:") print(f"Status: {response.status_code}") print(response.text) print('-'*88) if __name__ == '__main__': usage_demo()

Generate a presigned POST request to upload a file.

class BucketWrapper: def __init__(self, bucket): self.bucket = bucket self.name = bucket.name def generate_presigned_post(self, object_key, expires_in): """ Generate a presigned Amazon S3 POST request to upload a file. A presigned POST can be used for a limited time to let someone without an AWS account upload a file to a bucket. :param object_key: The object key to identify the uploaded object. :param expires_in: The number of seconds the presigned POST is valid. :return: A dictionary that contains the URL and form fields that contain required access data. """ try: response = self.bucket.meta.client.generate_presigned_post( Bucket=self.bucket.name, Key=object_key, ExpiresIn=expires_in) logger.info("Got presigned POST URL: %s", response['url']) except ClientError: logger.exception( "Couldn't get a presigned POST URL for bucket '%s' and object '%s'", self.bucket.name, object_key) raise return response
  • Find instructions and more code on GitHub.

Ruby
SDK for Ruby

require "aws-sdk-s3" require "net/http" # Creates a presigned URL that can be used to upload content to an object. # # @param bucket [Aws::S3::Bucket] An existing Amazon S3 bucket. # @param object_key [String] The key to give the uploaded object. # @return [URI, nil] The parsed URI if successful; otherwise nil. def get_presigned_url(bucket, object_key) url = bucket.object(object_key).presigned_url(:put) puts "Created presigned URL: #{url}." URI(url) rescue Aws::Errors::ServiceError => e puts "Couldn't create presigned URL for #{bucket.name}:#{object_key}. Here's why: #{e.message}" end def run_demo bucket_name = "doc-example-bucket" object_key = "my-file.txt" object_content = "This is the content of my-file.txt." bucket = Aws::S3::Bucket.new(bucket_name) presigned_url = get_presigned_url(bucket, object_key) return unless presigned_url response = Net::HTTP.start(presigned_url.host) do |http| http.send_request("PUT", presigned_url.request_uri, object_content, "content_type" => "") end case response when Net::HTTPSuccess puts "Content uploaded!" else puts response.value end end run_demo if $PROGRAM_NAME == __FILE__
  • Find instructions and more code on GitHub.