---
title: "Presigned URLs"
description: "Generate time-limited signed URLs for direct uploads and downloads without exposing credentials."
url: https://edge.network/docs/storage/presigned-urls/
---

# Presigned URLs

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.

[SDK Examples](https://edge.network/docs/storage/sdk-examples) [Multipart Uploads](https://edge.network/docs/storage/multipart-uploads)
[Back to Docs](https://edge.network/docs) [Need help?](https://edge.network/support)
