How to Upload Files to Amazon S3 Using Pre-signed URLs

Bryan Joseph
Revelry
Published in
3 min readJan 30, 2018

In this post, I’ll show you how to upload files to Amazon S3 using pre-signed URLs from the web and from React Native.

If uploading files to Amazon S3, a preferred method is to use pre-signed URLs. Pre-signed URLs are URLs that have been signed using AWS credentials. They give applications or users temporary permission to upload files to that URL. This is safer because the application or user uploading files will never see any AWS credentials.

I’m not going to go into the specifics of creating pre-signed URLs.

There are libraries in most languages to help with their creation. You may also decide to implement it yourself. Here, I’m presuming that you have the ability to generate pre-signed URLs and that you can send requests to a server to receive a URL as a response.

It’s time to upload images!

Upload to Amazon S3 From the Web

Our first example will be from the web. Let’s say you have a form where users can upload avatar images. When the user selects an image, you want to start the process of uploading an image.

function makeS3Request(data, file) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve(data.url) } else { reject({ status: xhr.status, statusText: xhr.statusText, }) } } } xhr.open('PUT', data.signed_request) xhr.send(file) }) } async function uploadFileToS3(file, urlElement, imagePreviewElement) { try { const response = await fetch( `/uploads/sign?file_name=${file.name}&file_type=${file.type}` ) const {data} = await response.json() const url = await makeS3Request(data, file) if (urlElement) { // Save image to hidden field urlElement.value = url } if (imagePreviewElement) { // Preview Image imagePreviewElement.src = url } } catch (e) { alert('Could not upload file.') } } const imageUploadElement = document.getElementById('avatar_uploader') if (imageUploadElement) { // Let's set up an event handler on the file handler imageUploadElement.onchange = () => { const file = imageUploadElement.files[0] if (file === null) { alert('No file selected.') } else { // function to handle S3 uploading uploadFileToS3( file, document.getElementById('avatar_url'), document.getElementById('avatar_preview') ) } } }

Upload to Amazon S3 From React Native

Let’s now do the same from React Native.

function makeS3Request(data, file) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve(data.url) } else { reject({ status: xhr.status, statusText: xhr.statusText, }) } } } xhr.open('PUT', data.signed_request) xhr.setRequestHeader('Content-Type', file.type) xhr.send({ uri: file.uri, type: data.file.type, name: data.file.name, }) }) } async function upload(file) { const response = await fetch(`https://example.com/uploads/sign?file_name=${file.name}&file_type=${file.type}`) const {data} = await response.json() return await makeS3Request(data, file) }

In both examples, XMLHttpRequest is used. The code between the web and React Native examples only slightly differ.

Happy Uploading!

Originally published at revelry.co on January 30, 2018.

--

--