This example demonstrates two mechanisms that a web browser can use to upload a file directly from a web browser to a Backblaze B2 Cloud Object Storage Bucket, without sending the file contents via a web server that you control:
- Using an S3 presigned URL and the PutObject operation.
- Using the
b2_upload_file
Backblaze B2 Native API operation.
The b2_upload_file
example was inspired by and borrows from Matt Welke's upload-file-to-backblaze-b2-from-browser-example. Many thanks to Matt for writing and publishing that code!
Both examples use a Node.js back end app that is configured with a Backblaze B2 application key, its ID, and other settings.
Note: for both mechanisms, the maximum file size that may be uploaded is 5 GB. You must split larger files into parts between 5 MB and 5 GB in size and use either the S3 Multipart operations or the B2 Native API equivalents.
Since the presigned URL includes the object key (filename), after the user clicks the upload button, the front end JavaScript code uses the fetch()
API to retrieve a presigned URL from the back end, passing the filename as a query parameter. The front end then uses fetch()
to PUT the file directly to Backblaze B2 via the S3-compatible API's PutObject operation.
In this example, the back end calls b2_get_upload_url
, passing the bucket id, and receiving an upload URL and authorization token in the response. The back end then renders the upload URL and authorization token into the web page containing the file upload element. JavaScript on the front end uses the fetch()
API to POST the file directly to Backblaze B2.
Here's how the two mechanisms differ:
S3 Presigned URL | B2 b2_upload_file |
---|---|
You can configure the presigned URL to expire any time from one second (probably too short to be of any practical use!) to one week after it is created. | The auth token and upload URL are valid for 24 hours or until the endpoint rejects an upload. |
A presigned URL must be created for each file to be uploaded. | The client may use the auth token and upload URL to upload an arbitrary number of files. |
The presigned URL contains the bucket and filename of the file to be uploaded. | The auth token and upload URL apply to a given bucket. The client specifies the filename as an HTTP header when the file is uploaded. |
In general, you should use S3 presigned URLs, since you have greater control over their expiration. Use the b2_upload_file
operation only when you cannot provide a mechanism for the client to obtain a presigned URL containing an appropriate filename, or you are working with a bucket that does not support the S3-compatible API.
The example has two components:
- An Express back end. For S3, the back end creates a presigned URL, signed using the B2 application key. For B2, the back end calls
b2_get_upload_url
and renders the resulting upload URL and authorization token into the web page as hidden form fields. In neither case is the B2 application key exposed to the browser. - A front end JavaScript app that uploads a selected file from the browser. For the B2
b2_get_upload_url
mechanism, the app uses SubtleCrypto to perform SHA1 hashing.
Create a bucket and use the B2 CLI to apply custom CORS rules. The contents of the b2CorsRules.json
file in this repo can be used as an example. The policy allows downloads and uploads from any origin, via both the B2 Native and S3-compatible APIs. If you're using bash, or a similar shell, you can use command substitution ($(...)
) to reference the JSON file with the CORS policy:
b2 update-bucket --cors-rules "$(cat b2CorsRules.json)" yourBucketName
You should see your CORS policy in the output from the b2
command. For example:
% b2 update-bucket --cors-rules "$(cat b2CorsRules.json)" metadaddy-public
{
"accountId": "15f935cf4dcb",
"bucketId": "f1f51fb913357c4f74ed0c1b",
"bucketInfo": {},
"bucketName": "metadaddy-public",
"bucketType": "allPublic",
"corsRules": [
{
"allowedHeaders": [
"authorization",
"content-type",
"x-bz-file-name",
"x-bz-content-sha1"
],
"allowedOperations": [
"b2_download_file_by_id",
"b2_upload_part",
"b2_upload_file",
"s3_put",
"b2_download_file_by_name",
"s3_get"
],
"allowedOrigins": [
"*"
],
"corsRuleName": "downloadFromAnyOriginWithUpload",
"exposeHeaders": null,
"maxAgeSeconds": 3600
}
],
"defaultRetention": {
"mode": null
},
"defaultServerSideEncryption": {
"mode": "none"
},
"isFileLockEnabled": false,
"lifecycleRules": [],
"options": [
"s3"
],
"replication": {
"asReplicationDestination": null,
"asReplicationSource": null
},
"revision": 8
}
Make a note of the bucketId
value - you'll need that in the next step.
Run npm install
.
Copy the provided .env.template
to .env
and edit it to include the following values:
B2_APPLICATION_KEY_ID=Your B2 application key id
B2_APPLICATION_KEY=Your B2 application key
B2_BUCKET_ID=The ID of the B2 bucket you're uploading files into.
B2_BUCKET_NAME=The name of the B2 bucket you're uploading files into.
AWS_ENDPOINT_URL=The bucket endpoint, prepended with `https://`, for example, `https://s3.us-west-004.backblazeb2.com`
AWS_REGION=The region segment of the bucket endpoint, for example. `us-west-004`
Run the app with DEBUG=b2-browser-upload:* npm start
.
Choose a file and upload it: