Working with Amazon S3 presigned URLs in Visual Studio
Tags: aws, s3
Published: 2022-02-07 16:58:00

I noticed a little [flurry of interest on Twitter recently](https://twitter.com/steffeng/status/1486617289952837636), after it was noticed that it’s now possible to create presigned URLs for objects in Amazon S3 storage buckets using the AWS Management Console. Whilst it’s always cool to get a positive reaction for customer-facing enhancements, I do recall thinking to myself “Pffft, .NET developers using the AWS Toolkit for Visual Studio have had this ability since v1 of our toolkit, back in 2011!”.

## What's a "presigned URL"?
Objects (files) in an S3 storage bucket are private by default. While you could share objects in a bucket by relaxing permissions, on either specific objects or the entire bucket. this really isn’t a good practice. Who knows what data you’ll put into the bucket in future, having forgotten that you relaxed permissions….and now you have a data leak ☹.

A presigned URL is simply a generated, time-limited URL to an object that you can use to share the object with others. When you create a presigned URL, you supply the bucket and object name (the object key, in AWS parlance), the allowed HTTP method, an expiration date and time, and your security credentials (which can be temporary, token-based time limited credentials too). If you use token-based credentials, the link expires when the token expires, even if this is earlier than the requested link duration. The maximum duration you can request for a presigned URL is 7 days.

The URL you get back can be shared with others, who can then access the object – even it is otherwise private. Therefore, you should obviously be careful when sharing them. Presigned URLs can be used to download, upload, and delete objects depending on the method encoded in the URL. I use presigned URLs frequently, to share large files with colleagues. This allows me to follow best practices and otherwise keep all my buckets and objects in them private and accessible only by me.

Essentially, a presigned URL contains a bearer token whose permissions are scoped by the permissions granted to whoever (or whatever) created the URL. This means a presigned URL grants no additional permissions to the consumer beyond those of the creator. For example, if my account doesn’t have permission to get (download) an object, a presigned URL I create, with HTTP method GET, to the object will fail to work - for me and anyone I share it with. It’s also possible to further restrict usage of a presigned URL to specific network paths, although not when creating them through the toolkits. See **Limiting presigned URL capabilities** in the [S3 user guide](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html).

## The AWS Toolkit for Visual Studio
Ok, now to the toolkit. If you’ve not seen or heard of it the toolkit is a free extension, available on the Visual Studio marketplace, that supports [Visual Studio 2017/2019](https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.AWSToolkitforVisualStudio2017), and [Visual Studio 2022](https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.AWSToolkitforVisualStudio2022) (there’s also a [free toolkit for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=AmazonWebServices.aws-toolkit-vscode), which also supports creating presigned URLs without leaving the editor).

The Visual Studio toolkit surfaces an explorer window in the IDE that allows you to work with several AWS services (S3, EC2, DynamoDB, Lambda, et al) from within the convenience of the IDE and not have to jump out to a web browser to use the console, and several wizards making it easy to deploy code to Elastic Beanstalk (web apps), Lambda (serverless functions and apps), Elastic Container Service, and CloudFormation (infrastructure as code).

## Generating a presigned URL using the toolkit
To create a presigned URL to an object using the toolkit, you first need to open a view onto the bucket’s objects. From the AWS Explorer window (View -> AWS Explorer, if the window’s not visible), expand the Amazon S3 hierarchy and locate the entry for the bucket. Double-click it, or use the context menu, to open the view:

![Opening an S3 bucket view in Visual Studio](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/syfo28gkezp8yfutuo29.png)

Although S3 is a flat object store, not a hierarchical file system, the toolkit’s organizes objects in the bucket into “folders”, parsing on the / character in the object keys. So, you might need to traverse down one or more of those simulated folders to find the object you want. Let's generate a presignedURL for an object at the root of the bucket.

To do that, right-click on the object to share a link to and select “Create Pre-Signed URL…”:

![S3 object context menu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zt4atgb48d9jj3gi6764.png)

In the resulting dialog I select the HTTP method (GET or PUT, the toolkit doesn’t support DELETE) and the expiry date and time. I can also set a content-type if needed. Then I click the Generate button to obtain the URL:

![Presigned URL dialog](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lf90yupytr1kxruaudqr.png)

The Copy button copies the generated URL to the clipboard. I can now click OK to dismiss the dialog and head back to whatever content I was writing (email, etc.), and paste the link. The recipient will then be able to use the link to download the object, even though it’s private, until 12PM on Feb 7th in this example.

If you’re a Visual Studio Code user, you can do this too but the process is a little different. In the VS Code toolkit, you navigate objects in a bucket directly within the explorer pane. The context menu on an object shows a command to generate a URL (here I’m going to generate a URL for an object in a “subfolder“):

![Generating a presigned URL in Visual Studio Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7i3frc5euxm5cx6w2e7s.png)

You’re then asked for the validity duration, in minutes – there’s no dialog as in Visual Studio, and you can’t change the method (it’s always GET) or set a custom content type:

![Setting the expiry in Visual Studio Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4b8vu6mkpmazr79yuwmc.png)

Press Enter once you’ve set the duration and the toolkit creates a URL, automatically copies it to the clipboard, ready to paste elsewhere. It also displays confirmation in the status bar:

![Status bar confirmation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5gdnryo62wv8i7bhcpmd.png)

## I don’t use an IDE toolkit, now what?
To wrap up the post, I wanted to note that it’s also possible to create presigned URLs from command line tools. Using the [AWS Tools for PowerShell](https://aws.amazon.com/powershell/), the `Get-S3PresignedUrl` is what you need [(docs here)](https://docs.aws.amazon.com/powershell/latest/reference/items/Get-S3PreSignedURL.html). It accepts a `DateTime` object to set the expiry, defaulting to HTTPS protocol and GET as the method:

```powershell
Get-S3PresignedUrl -BucketName steve-presignedurldemo -Key dotNETAndPowerShellOnAWSBoothVideo2021.mp4 -Expire 2022-02-06
https://steve-presignedurldemo.s3.us-west-2.amazonaws.com/dotNETAndPowerShellOnAWSBoothVideo2021.mp4?X-Amz-Expires=217008&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-SignedHeaders=host&X-Amz-Signature=5982...fb4b
```
If you use the [AWS CLI](https://aws.amazon.com/cli/), you use `aws s3 presign` [(docs here)](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/presign.html), which defaults to a one-hour expiry if not specified:

```bash
aws s3 presign s3://steve-presignedurldemo/dotNETAndPowerShellOnAWSBoothVideo2021.mp4
https://steve-presignedurldemo.s3.us-west-2.amazonaws.com/dotNETAndPowerShellOnAWSBoothVideo2021.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=f7b8...29bdf
```

_Happy presigning – and welcome to the party, (management console) pal!_