Upload a file to R2 using a pre-signed url
In this Article
Overview
In this article I’ll show a practical example of how to use a pre-signed url to upload a file to Cloudflare R2. Objects in R2 buckets are private by default. That means the user will need permission to be able to upload a file on the client side. In this case we can grant the user with temporary permission that’s restricted to the specific action we want the user to take using a pre-signed url.
Signing the url
We are going to use the aws4fetch library to sign the url. Keep in mind for this to work you’ll might need to update the cors settings of your bucket. You will need to generate the access_key_id and secret_access_key for your R2 bucket. You’ll also need to bind your bucket to your pages app or cloudflare worker. Here is what the pill code looks like:
Now here is the pill of code:
import { AwsClient } from 'aws4fetch'
export const onRequestPost = async (context: any): Promise<Response> => {
const { env } = context
// the bound bucket
const myBucket = env.MY_BUCKET
// my cloudflare account id
const cfAccountId = env.CF_ACCOUNT_ID
// init the client
const r2: AwsClient = new AwsClient({
accessKeyId: env.R2_ACCESS_KEY_ID,
secretAccessKey: env.R2_SECRET_ACCESS_KEY,
})
// allow the user to perform operations under the assets folder in my bucket
const url = new URL(`https://${cfAccountId}.r2.cloudflarestorage.com/${myBucket}/assets`)
// Specify a custom expiry for the presigned URL, in seconds
url.searchParams.set('x-Amz-Expires', '3600')
// allow the user to perform a PUT (upload) operation
const mySignedUrl = await r2.sign(
new Request(url, {
method: 'PUT',
}),
{
aws: { signQuery: true },
},
)
// return the signed url
return Promise.resolve(new Response(JSON.stringify({ signedUrl: mySignedUrl.url }), { status: 200 }))
}
Now the client can read the signedUrl from the response body and use it for uploading a file.