Pre-signed URLs
A pre-signed URL embeds a short-lived signature in a URL, granting the bearer permission to perform exactly one S3 operation on exactly one object. Use them when you need to:
- Let a user download a private object via a normal browser link.
- Let a browser upload directly to Filebase without your access key ever touching the client.
- Share a temporary download link with a third party.
The pre-signed URL is generated client-side using your access key — Filebase doesn't see it until the recipient uses it.
How they work
- You decide which operation (
GET,PUT, etc.) and which object. - You ask the SDK to compute a SigV4 signature for that exact request, with an expiration time.
- The SDK encodes the signature, your access key ID, the date, and the expiry into URL query parameters.
- The result is a normal HTTPS URL anyone can use until the signature expires.
The recipient doesn't need an access key. They don't need any S3 client. They just need an HTTP client.
Generate a download URL
AWS CLI
aws --endpoint https://s3.filebase.io s3 presign s3://my-bucket/private.pdf
By default the URL is valid for 1 hour. Override with --expires-in <seconds>:
aws --endpoint https://s3.filebase.io s3 presign s3://my-bucket/private.pdf --expires-in 86400
AWS SDK for JavaScript v3
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const s3 = new S3Client({
endpoint: 'https://s3.filebase.io',
region: 'auto',
credentials: { accessKeyId: KEY, secretAccessKey: SECRET },
});
const url = await getSignedUrl(
s3,
new GetObjectCommand({ Bucket: 'my-bucket', Key: 'private.pdf' }),
{ expiresIn: 3600 },
);
console.log(url);
AWS SDK for Python (boto3)
url = s3.generate_presigned_url(
'get_object',
Params={'Bucket': 'my-bucket', 'Key': 'private.pdf'},
ExpiresIn=3600,
)
AWS SDK for Go v2
presigner := s3.NewPresignClient(client)
req, err := presigner.PresignGetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("private.pdf"),
}, s3.WithPresignExpires(time.Hour))
fmt.Println(req.URL)
Generate an upload URL
A pre-signed PutObject URL lets a browser upload directly to Filebase, bypassing your application server entirely:
AWS SDK for JavaScript v3
import { PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const url = await getSignedUrl(
s3,
new PutObjectCommand({
Bucket: 'uploads',
Key: `user-${userId}/${filename}`,
ContentType: 'image/jpeg',
}),
{ expiresIn: 600 },
);
return url;
The browser then PUTs the file directly:
await fetch(presignedUrl, {
method: 'PUT',
body: fileBlob,
headers: { 'Content-Type': 'image/jpeg' },
});
See browser uploads for the full pattern, including handling CORS.
AWS SDK for Python (boto3)
url = s3.generate_presigned_url(
'put_object',
Params={
'Bucket': 'uploads',
'Key': f'user-{user_id}/{filename}',
'ContentType': 'image/jpeg',
},
ExpiresIn=600,
)
Expiration
Pre-signed URLs expire after the time you specify (ExpiresIn, in seconds). Until then they can be used as many times as the recipient wants — pre-signed URLs are not single-use. After expiry the URL returns 403 SignatureExpired from Filebase.
A reasonable default is 1 hour for downloads and 10 minutes for uploads, but tune for your use case.
Security considerations
- A pre-signed URL is as powerful as the operation it signs. A pre-signed
PutObjectURL lets the bearer overwrite that exact key with arbitrary content. Generate URLs only for the specific operations and keys you intend. - Never log or persist pre-signed URLs in places where untrusted parties might see them. They effectively contain a short-lived bearer token.
- For browser uploads, constrain the upload by including
ContentType,Content-Lengthranges, or a custom condition policy. The SDK enforces these constraints by signing them into the URL — the browser cannot deviate without invalidating the signature.
Pre-signed URLs and the CDN
Pre-signed URL responses are not aggressively cached at the Filebase CDN — the cache key includes the signature, so distinct URLs for the same object are cache misses. For high-traffic public distribution, prefer a public bucket over rotating pre-signed URLs.