Storage
Presigned URLs
Generate time-limited signed URLs that allow anyone to upload or download objects directly, without exposing your credentials. Ideal for browser uploads, mobile apps and sharing private files.
On this page7 sections
How presigned URLs work#
A presigned URL is a time-limited, self-authenticating URL that grants temporary access to a specific object. The URL embeds the access credentials as query parameters using AWS Signature V4, so the recipient doesn’t need API keys.
- Presigned uploads: let users upload files directly to storage from their browser or app. No server-side proxy is needed; the client PUTs directly to the signed URL.
- Presigned downloads: share private files with time-limited links. Give a user a URL to download their invoice, report or asset. The link expires after the set duration.
Two ways to generate presigned URLs#
- Using S3 SDKs (recommended): generate presigned URLs client-side or server-side using any AWS S3 SDK. This is the standard approach and works identically to AWS S3. Requires your access key and secret key.
- Using the Edge API: call
POST /api/storage/buckets/:name/presignwith your Edge API token. The server generates the presigned URL for you, so no S3 credentials are needed on the client.
SDK examples#
For JavaScript and Node.js, install the S3 client and presigner:
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presignerGenerate a presigned upload URL#
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
const client = new S3Client({
endpoint: 'https://storage.edge.network',
region: 'us-east-1',
forcePathStyle: true,
credentials: {
accessKeyId: process.env.EDGE_ACCESS_KEY,
secretAccessKey: process.env.EDGE_SECRET_KEY
}
})
// Generate a presigned upload URL (valid for 1 hour)
const url = await getSignedUrl(client, new PutObjectCommand({
Bucket: 'my-bucket',
Key: 'uploads/photo.jpg',
ContentType: 'image/jpeg',
}), { expiresIn: 3600 })import os
import boto3
client = boto3.client(
's3',
endpoint_url='https://storage.edge.network',
aws_access_key_id=os.environ['EDGE_ACCESS_KEY'],
aws_secret_access_key=os.environ['EDGE_SECRET_KEY'],
region_name='us-east-1'
)
# Generate a presigned upload URL (valid for 1 hour)
url = client.generate_presigned_url(
'put_object',
Params={
'Bucket': 'my-bucket',
'Key': 'uploads/photo.jpg',
'ContentType': 'image/jpeg',
},
ExpiresIn=3600
)
print(url)Generate a presigned download URL#
Both examples reuse the client created above.
import { GetObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
// Generate a presigned download URL (valid for 15 minutes)
const url = await getSignedUrl(client, new GetObjectCommand({
Bucket: 'my-bucket',
Key: 'invoices/invoice-001.pdf',
}), { expiresIn: 900 })# Generate a presigned download URL (valid for 15 minutes)
url = client.generate_presigned_url(
'get_object',
Params={
'Bucket': 'my-bucket',
'Key': 'invoices/invoice-001.pdf',
},
ExpiresIn=900
)
print(url)Upload from a browser#
Upload a file from the browser using the presigned URL:
// Browser: upload a file using the presigned URL
const fileInput = document.querySelector('input[type="file"]')
const file = fileInput.files[0]
const response = await fetch(presignedUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type,
},
})
if (response.ok) {
console.log('Upload complete')
}Use a presigned URL with cURL#
Upload with a presigned URL:
# Upload using the presigned URL
curl -X PUT "$PRESIGNED_URL" \
-H "Content-Type: image/jpeg" \
--data-binary @photo.jpgDownload with a presigned URL:
# Download using the presigned URL
curl -o invoice.pdf "$PRESIGNED_URL"Edge API#
If you don’t want to manage S3 credentials on the client, you can generate presigned URLs server-side via the Edge API using your account’s Bearer token.
POST /api/storage/buckets/:name/presign#
| Parameter | Type | Required | Description |
|---|---|---|---|
key |
string | Yes | Object key (path) within the bucket |
action |
string | No | download (default) or upload |
expires |
string | No | Duration: 15m, 1h (default), 7d (max) |
Generate an upload URL:
# Generate a presigned upload URL via the Edge API
curl -X POST https://api.edge.network/api/storage/buckets/my-bucket/presign \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"key": "uploads/photo.jpg",
"action": "upload",
"expires": "1h"
}'Response:
{
"url": "https://storage.edge.network/my-bucket/uploads/photo.jpg?X-Amz-Algorithm=...",
"method": "PUT",
"expires": "2026-03-12T01:00:00Z"
}Generate a download URL:
# Generate a presigned download URL via the Edge API
curl -X POST https://api.edge.network/api/storage/buckets/my-bucket/presign \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"key": "invoices/invoice-001.pdf",
"expires": "15m"
}'Common use cases#
- User avatar uploads: generate a presigned PUT URL server-side, return it to the browser, and let the user upload their photo directly to storage.
- Private file sharing: generate a presigned GET URL for an invoice or report and send the link to the user. It expires after the set duration.
- Mobile app uploads: your backend generates a presigned URL, sends it to the mobile app, and the app uploads directly. No proxy, no extra bandwidth on your server.
- Third-party integrations: give a partner or webhook a presigned URL to upload data into your bucket without sharing credentials.
Security considerations#
Next steps
Something unclear or out of date? Tell us