Edge

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.

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 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

1 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.

2 Using the Edge API

Call POST /api/storage/buckets/:name/presign with your Edge API token. The server generates the presigned URL for you — no S3 credentials needed on the client.

SDK Examples

JavaScript / Node.js

Install the S3 client and presigner:

npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner

Generate 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 })

Generate a presigned download URL

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 })

Upload from a 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')
}

Python

Generate a presigned upload URL

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

# 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)

cURL

Upload with a presigned URL

# Upload using the presigned URL
curl -X PUT "$PRESIGNED_URL" \
  -H "Content-Type: image/jpeg" \
  --data-binary @photo.jpg

Download 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. 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

  • URLs are bearer tokens. Anyone with the URL can use it until it expires. Share them over secure channels (HTTPS, encrypted messages).
  • Keep expiry times short. Use the minimum duration needed — 15 minutes for downloads, 1 hour for uploads. Maximum is 7 days.
  • URLs are scoped to a single object. A presigned URL for photos/image.jpg cannot be used to access any other object.
  • Revoking access. Delete or rotate the access key used to generate the URL. All presigned URLs created with that key become invalid immediately.