Guide to Pre-Signed URLs

Guide to Pre-Signed URLs

Stop sharing your master keys. Learn how to use pre-signed URLs to grant secure, temporary access to your Filebase buckets—perfect for private sharing and direct client uploads.

AuthorFilebase Team
CategoryGuides

The Problem: Sharing Private Data is Hard

Imagine you're building an application that stores user-generated content—like private documents, invoices, or personal photos. You store these files in a private Filebase bucket to keep them secure.

But now, you need to show a specific file to a specific user. How do you do it?

  • Option A (The Bad Way): Make the bucket public. (Security nightmare.)
  • Option B (The Slow Way): Download the file to your server, then stream it to the user. (Wastes bandwidth, adds latency, and crashes your server under load.)
  • Option C (The Right Way): Use a Pre-Signed URL.

What is a Pre-Signed URL?

Think of a pre-signed URL like a digital guest pass.

When you give a guest a pass to your office, you don't give them your master keys. You give them a temporary badge that opens one specific door for a limited amount of time.

A pre-signed URL works exactly the same way. It is a generated link that grants temporary access to a specific object in your private bucket. The URL contains a cryptographic signature that verifies you authorized the request, without ever exposing your actual API credentials.

Why You Should Use Them

Pre-signed URLs aren't just a security feature; they are a performance optimization.

  • Zero-Trust Security: Keep your buckets private (ACL: private) by default. Only grant access when explicitly needed.
  • Offload Bandwidth: Instead of routing file traffic through your application servers, users download directly from Filebase's decentralized edge network. This creates a "serverless" data transfer architecture.
  • Direct Uploads: Let users upload large files (like videos) directly to your bucket from their browser. Your server simply generates the permission, and the client handles the heavy lifting.

How It Works Under the Hood

Since Filebase is S3-compatible, pre-signed URLs work by leveraging the standard AWS Signature Version 4 protocol.

  1. The Request: Your application defines what action is allowed (e.g., GET a specific file) and for how long (e.g., 15 minutes).
  2. The Signature: Your code uses your Filebase Secret Access Key to cryptographically sign this request.
  3. The URL: The result is a standard URL with a query string containing the signature, expiration time, and credentials.
  4. Verification: When the user clicks the link, Filebase checks the signature. If it matches and the time hasn't expired, the request is allowed.

Implementation Guide

Because Filebase is 100% S3-compatible, you don't need any special proprietary SDKs. You can use the standard tools you already know and trust.

1. Using the AWS CLI

The quickest way to test pre-signed URLs is with the command line. This is great for debugging or generating one-off links for administrative tasks.

terminal
# Prerequisite: Configure your AWS CLI with Filebase credentials
# aws configure --profile filebase

# Generate a download link valid for 1 hour (3600 seconds)
aws s3 presign s3://my-private-bucket/secret-document.pdf \
    --endpoint-url https://s3.filebase.com \
    --expires-in 3600

# Output:
# https://s3.filebase.com/my-private-bucket/secret-document.pdf?AWSAccessKeyId=...&Signature=...&Expires=...

2. Python (Boto3)

For backend applications, Python's boto3 library makes generation trivial. This is the standard way to generate secure links for a Django or Flask app.

generate_url.py
import boto3
from botocore.config import Config

# Initialize the S3 client for Filebase
s3 = boto3.client('s3',
    endpoint_url='https://s3.filebase.com',
    aws_access_key_id='YOUR_FILEBASE_ACCESS_KEY',
    aws_secret_access_key='YOUR_FILEBASE_SECRET_KEY',
    config=Config(signature_version='s3v4')
)

def generate_download_link(bucket_name, object_key, expiration=3600):
    """
    Generate a pre-signed URL to share an S3 object
    """
    try:
        response = s3.generate_presigned_url('get_object',
            Params={
                'Bucket': bucket_name,
                'Key': object_key
            },
            ExpiresIn=expiration
        )
        return response
    except Exception as e:
        print(f"Error generating URL: {e}")
        return None

# Example usage:
# url = generate_download_link('my-bucket', 'user-uploads/report.pdf')
# print(url)

3. Node.js (AWS SDK v3)

Modern JavaScript applications use the AWS SDK v3. Note that v3 is modular, so you'll import the s3-request-presigner package specifically.

presigner.js
import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3Client = new S3Client({
  region: "us-east-1",
  endpoint: "https://s3.filebase.com",
  credentials: {
    accessKeyId: process.env.FILEBASE_ACCESS_KEY,
    secretAccessKey: process.env.FILEBASE_SECRET_KEY,
  },
});

/**
 * Generate a URL for uploading a file directly to Filebase
 * @param {string} bucket - The bucket name
 * @param {string} key - The filename to save as
 */
export async function generateUploadUrl(bucket, key) {
  const command = new PutObjectCommand({
    Bucket: bucket,
    Key: key,
    ContentType: 'image/jpeg', // Optional: Restrict content type
  });

  // URL valid for 15 minutes
  return await getSignedUrl(s3Client, command, { expiresIn: 900 });
}

/**
 * Generate a secure download URL
 */
export async function generateDownloadUrl(bucket, key) {
  const command = new GetObjectCommand({
    Bucket: bucket,
    Key: key,
  });

  // URL valid for 1 hour
  return await getSignedUrl(s3Client, command, { expiresIn: 3600 });
}

Advanced Configuration

Simply generating a URL is often not enough for production systems. You may need to enforce strict security policies on how the URL is used.

Restricting Uploads

When allowing users to upload files, you should never trust the client blindly. You can bake restrictions directly into the pre-signed URL signature. If the user tries to upload a file that doesn't match these conditions, Filebase will reject it.

  • Content-Length-Range: Prevent users from uploading massive files that eat your storage quota.
  • Content-Type: Ensure that a "profile picture" upload is actually an image, not a malicious script.
advanced-policy.json
{
  "expiration": "2026-01-25T12:00:00.000Z",
  "conditions": [
    {"bucket": "user-uploads"},
    ["starts-with", "$key", "avatars/"],
    {"acl": "private"},
    ["starts-with", "$Content-Type", "image/"],
    ["content-length-range", 1048, 10485760]
  ]
}

In this policy: The file must be an image, must be between 1KB and 10MB, and must be uploaded to the 'avatars/' folder.

Best Practices Checklist

Before rolling this out to production, run through this quick security checklist.

Do This

  • Set short expiration times (e.g., 15 minutes for uploads).
  • Use random filenames to prevent overwriting existing data.
  • Validate file types on your backend before generating the URL.
  • Log who generated each URL for audit trails.

Don't Do This

  • Don't hardcode credentials in your frontend code.
  • Don't create URLs with infinite expiration (maximum is usually 7 days).
  • Don't allow public write access to your bucket.

Troubleshooting Common Issues

SignatureDoesNotMatch Error
This is the most common error. It usually means the headers sent by the client don't match the headers used to generate the signature. Ensure your Content-Type matches exactly.
Clock Skew
If your server's system time is out of sync, the generated timestamp will be invalid. Ensure your server uses NTP to stay synchronized.

Ready to secure your data?

Pre-signed URLs are the industry standard for secure file sharing. By combining them with Filebase, you get the best of both worlds: the familiar S3 developer experience and the resilience of decentralized storage.

Start by generating your first URL in the CLI, and then integrate it into your application workflow.