Creating a secure method for users to upload files directly to an S3 bucket is a common requirement in modern web applications.
By using pre-signed URLs, you can allow a client to upload a file directly to S3 without exposing your AWS credentials, they also provide a secure mechanism to upload files directly to S3 from a client, avoiding the need to pass the file data through your server.
In this tutorial, we will leverage the Nitric SDK in Python to generate secure upload URLs for an S3 bucket, which can then be used from your front-end application.
If you haven’t used the Nitric SDK before, then start with this tutorial.
Step 1: Initialize Nitric Bucket Instance
Inside the main
function, initialize a new Nitric bucket instance with the name of your S3 bucket.
from nitric.resources import api, bucket
from nitric.application import Nitric
from nitric.context import HttpContext
main_api = api('main')
images = bucket('images').allow('reading')
Step 2: Generate a Secure Upload URL
Now, generate a secure upload URL for a specific file. In this example, we are creating a URL for uploading a file named cat.png
. We also specify a time-to-live (TTL) for the URL of 300 seconds (5 minutes).
from nitric.resources import bucket
from nitric.application import Nitric
assets = bucket('assets').allow('reading')
logo = assets.file('images/logo.png')
logo_url = await logo.download_url(expiry=300)
Nitric.run()
Now, you have a secure upload URL for your cat.png
file. You can use this URL in your front-end application to securely upload the cat.png
file to your S3 bucket. The URL will expire after 1 hour, ensuring that the upload URL cannot be misused after a reasonable amount of time.
This setup abstracts much of the boilerplate and complexity involved in generating pre-signed URLs for S3, allowing developers to focus more on building their applications.
In the case that you want to get an image url for rendering, then simply redirect the URL with a 303 status and a location.
from nitric.resources import api, bucket
from nitric.application import Nitric
from nitric.context import HttpContext
main_api = api('main')
images = bucket('images').allow('reading')
@main_api.get('/images/:id')
async def get_image(ctx: HttpContext):
id = ctx.req.params['id']
url = await images.file(id).download_url()
ctx.res.status = 303
ctx.res.headers['Location'] = [url]
Nitric.run()
The Nitric SDK offers a streamlined approach to interacting with AWS S3, among other cloud services, in a cloud-agnostic manner.