You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* update Presigned URL vs Binding
* Apply suggestions from code review
* update limitations
* Apply suggestions from code review
* Cleaning up structure of the doc with tabs.
* Small fix
* Further language clarification
---------
Co-authored-by: Jun Lee <[email protected]>
Copy file name to clipboardExpand all lines: src/content/docs/r2/api/s3/presigned-urls.mdx
+74-40Lines changed: 74 additions & 40 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,6 +3,8 @@ title: Presigned URLs
3
3
pcx_content_type: concept
4
4
---
5
5
6
+
import {Tabs, TabItem } from"~/components";
7
+
6
8
Presigned URLs are an [S3 concept](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html) for sharing direct access to your bucket without revealing your token secret. A presigned URL authorizes anyone with the URL to perform an action to the S3 compatibility endpoint for an R2 bucket. By default, the S3 endpoint requires an `AUTHORIZATION` header signed by your token. Every presigned URL has S3 parameters and search parameters containing the signature information that would be present in an `AUTHORIZATION` header. The performable action is restricted to a specific resource, an [operation](/r2/api/s3/api/), and has an associated timeout.
7
9
8
10
There are three kinds of resources in R2:
@@ -50,16 +52,6 @@ R2 currently supports the following methods when generating a presigned URL:
50
52
51
53
`POST`, which performs uploads via native HTML forms, is not currently supported.
52
54
53
-
## Generate presigned URLs
54
-
55
-
Generate a presigned URL by referring to the following examples:
56
-
57
-
-[AWS SDK for Go](/r2/examples/aws/aws-sdk-go/#generate-presigned-urls)
58
-
-[AWS SDK for JS v3](/r2/examples/aws/aws-sdk-js-v3/#generate-presigned-urls)
59
-
-[AWS SDK for JS](/r2/examples/aws/aws-sdk-js/#generate-presigned-urls)
60
-
-[AWS SDK for PHP](/r2/examples/aws/aws-sdk-php/#generate-presigned-urls)
A valid alternative design to presigned URLs is to use a Worker with a [binding](/workers/runtime-apis/bindings/) that implements your security policy.
@@ -72,14 +64,33 @@ A binding is defined in the Wrangler file of your Worker project's directory.
72
64
73
65
:::
74
66
75
-
A possible use case may be restricting an application to only be able to upload to a specific URL. With presigned URLs, your central signing application might look like the following JavaScript code running on Cloudflare Workers, workerd, or another platform.
67
+
Refer to [Use R2 from Workers](/r2/api/workers/workers-api-usage/) to learn how to bind a bucket to a Worker and use the binding to interact with your bucket.
76
68
77
-
If the Worker received a request for `https://example.com/uploads/dog.png`, it would respond with a presigned URL allowing a user to upload to your R2 bucket at the `/uploads/dog.png` path.
69
+
## Generate presigned URLs
70
+
71
+
Generate a presigned URL by referring to the following examples:
72
+
73
+
-[AWS SDK for Go](/r2/examples/aws/aws-sdk-go/#generate-presigned-urls)
74
+
-[AWS SDK for JS v3](/r2/examples/aws/aws-sdk-js-v3/#generate-presigned-urls)
75
+
-[AWS SDK for JS](/r2/examples/aws/aws-sdk-js/#generate-presigned-urls)
76
+
-[AWS SDK for PHP](/r2/examples/aws/aws-sdk-php/#generate-presigned-urls)
A possible use case may be restricting an application to only be able to upload to a specific URL. With presigned URLs, your central signing application might look like the following JavaScript code running on Cloudflare Workers, `workerd`, or another platform (you might have to update the code based on the platform you are using).
82
+
83
+
If the application received a request for `https://example.com/uploads/dog.png`, it would respond with a presigned URL allowing a user to upload to your R2 bucket at the `/uploads/dog.png` path.
84
+
85
+
To create a presigned URL, you will need to either use a package that implements the signing algorithm, or implement the signing algorithm yourself. In this example, the `aws4fetch` package is used. You also need to have an access key ID and a secret access key. Refer to [R2 API tokens](/r2/api/tokens/) for more information.
78
86
79
87
```ts
80
88
import { AwsClient } from"aws4fetch";
81
89
82
-
const r2 =newAwsClient({
90
+
// Create a new client
91
+
// Replace with your own access key ID and secret access key
92
+
// Make sure to store these securely and not expose them
93
+
const client =newAwsClient({
83
94
accessKeyId: "",
84
95
secretAccessKey: "",
85
96
});
@@ -98,6 +109,7 @@ export default {
98
109
returnnewResponse("Missing a filepath", { status: 400 });
99
110
}
100
111
112
+
// Replace with your bucket name and account ID
101
113
const bucketName ="";
102
114
const accountId ="";
103
115
@@ -111,7 +123,7 @@ export default {
111
123
// Specify a custom expiry for the presigned URL, in seconds
112
124
url.searchParams.set("X-Amz-Expires", "3600");
113
125
114
-
const signed =awaitr2.sign(
126
+
const signed =awaitclient.sign(
115
127
newRequest(url, {
116
128
method: "PUT",
117
129
}),
@@ -128,12 +140,47 @@ export default {
128
140
} satisfiesExportedHandler;
129
141
```
130
142
131
-
Notice the total absence of any configuration or token secrets present in the Worker code. Instead, in your [Wrangler configuration file](/workers/wrangler/configuration/), you would create a [binding](/r2/api/workers/workers-api-usage/#3-bind-your-bucket-to-a-worker) to whatever bucket represents the bucket you will upload to. Additionally, authorization is handled in-line with the upload which can reduce latency.
143
+
## Differences between presigned URLs and R2 binding
144
+
145
+
- When using an R2 binding, you will not need any token secrets in your Worker code. Instead, in your [Wrangler configuration file](/workers/wrangler/configuration/), you will create a [binding](/r2/api/workers/workers-api-usage/#3-bind-your-bucket-to-a-worker) to your R2 bucket. Additionally, authorization is handled in-line, which can reduce latency.
146
+
- When using presigned URLs, you will need to create and use the token secrets in your Worker code.
147
+
148
+
In some cases, R2 bindings let you implement certain functionality more easily. For example, if you wanted to offer a write-once guarantee so that users can only upload to a path once:
149
+
150
+
- With R2 binding: You only need to pass the header once.
151
+
- With presigned URLs: You need to first sign specific headers, then request the user to send the same headers.
132
152
133
-
In some cases, Workers lets you implement certain functionality more easily. For example, if you wanted to offer a write-once guarantee so that users can only upload to a path once, with pre-signed URLs, you would need to sign specific headers and require the sender to send them. You can modify the previous Worker to sign additional headers:
153
+
<Tabs>
154
+
<TabItemlabel="R2 binding example">
155
+
156
+
If you are using R2 bindings, you would change your upload to:
// No objects will have been uploaded before September 28th, 2021 which
162
+
// is the initial R2 announcement.
163
+
uploadedBefore: newDate(1632844800000),
164
+
},
165
+
});
166
+
if (existingObject?.etag!==request.headers.get("etag")) {
167
+
returnnewResponse("attempt to overwrite object", { status: 400 });
168
+
}
169
+
```
170
+
171
+
When using R2 bindings, you may need to consider the following limitations:
172
+
173
+
- You cannot upload more than 100 MiB (200 MiB for Business customers) when using R2 bindings.
174
+
- Enterprise customers can upload 500 MiB by default and can ask their account team to raise this limit.
175
+
- Detecting [precondition failures](/r2/api/s3/extensions/#conditional-operations-in-putobject) is currently easier with presigned URLs as compared with R2 bindings.
176
+
177
+
Note that these limitations depend on R2's extension for conditional uploads. Amazon's S3 service does not offer such functionality at this time.
178
+
</TabItem>
179
+
<TabItemlabel="Presigned URL example">
180
+
You can modify the previous example to sign additional headers:
134
181
135
182
```ts
136
-
const signed =awaitr2.sign(
183
+
const signed =awaitclient.sign(
137
184
newRequest(url, {
138
185
method: "PUT",
139
186
}),
@@ -146,34 +193,21 @@ const signed = await r2.sign(
146
193
);
147
194
```
148
195
149
-
Note that the caller has to add the same `If-Unmodified-Since` header to use the URL. The caller cannot omit the header or use a different header. If the caller uses a different header, the presigned URL signature would not match, and they would receive a `403/SignatureDoesNotMatch`.
if (existingObject?.etag!==request.headers.get("etag")) {
166
-
returnnewResponse("attempt to overwrite object", { status: 400 });
167
-
}
204
+
});
168
205
```
169
206
170
-
Cloudflare Workers currently have some limitations that you may need to consider:
171
-
172
-
- You cannot upload more than 100 MiB (200 MiB for Business customers) to a Worker.
173
-
- Enterprise customers can upload 500 MiB by default and can ask their account team to raise this limit.
174
-
- Detecting [precondition failures](/r2/api/s3/extensions/#conditional-operations-in-putobject) is currently easier with presigned URLs as compared with R2 bindings.
207
+
Note that the caller has to add the same `If-Unmodified-Since` header to use the URL. The caller cannot omit the header or use a different header, since the signature covers the headers. If the caller uses a different header, the presigned URL signature would not match, and they would receive a `403/SignatureDoesNotMatch`.
175
208
176
-
Note that these limitations depends on R2's extension for conditional uploads. Amazon's S3 service does not offer such functionality at this time.
209
+
</TabItem>
210
+
</Tabs>
177
211
178
212
## Differences between presigned URLs and public buckets
0 commit comments