Advertisement
Cloud Storage Guide

Mastering S3 Presigned URLs
with Backblaze

Generate secure, time-limited access to private storage objects with S3-compatible APIs. Learn implementation, best practices, and cost optimization.

80%
Lower Storage Costs
100%
S3 Compatible
5min
Setup Time

S3 presigned URLs are cryptographically signed, time-limited links that grant temporary access to private objects in cloud storage. They're essential for secure file sharing without exposing credentials or making buckets public.

With Backblaze B2's S3-Compatible API, you get all the power of AWS S3 presigned URLs at a fraction of the costβ€”up to 80% cheaper! This guide covers implementation, security, and includes a memorable football analogy (Newcastle 2-1 Man City) to help you understand access control.

What is a Presigned URL? πŸ”

A presigned URL is a special web address that includes authentication information in the URL itself. It allows anyone with the link to access a private object without needing AWS credentials or authentication headers.

The signature encodes:

  • βœ“Who issued it: Your access key ID
  • βœ“What operation: GET (download), PUT (upload), DELETE, etc.
  • βœ“Which object: Bucket name and object key/path
  • βœ“When it expires: Unix timestamp for expiration

Key Benefit: Both AWS S3 and Backblaze B2 S3-Compatible APIs support presigned URLs, making them ideal for secure, credential-free data transfers across platforms.

Why Choose Backblaze? πŸ’°

S3 Compatible

Drop-in replacement for AWS S3. Use standard SDKs (boto3, AWS SDK) with just endpoint changes.

Massive Savings

Up to 80% cheaper storage and egress costs compared to AWS S3. Free egress with Bandwidth Alliance.

Enterprise Security

Same security model as AWS. Encrypted transfers, time-limited access, and cryptographic signatures.

Implementation Guide πŸš€

1

Create Application Key

Navigate to Backblaze console β†’ App Keys β†’ Create new key. Select S3 Compatible API and note your keyID and applicationKey.

2

Install AWS SDK

For Node.js: npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner. For Python: pip install boto3.

3

Configure Endpoint

Point SDK to Backblaze endpoint (e.g., s3.us-west-004.backblazeb2.com) instead of AWS endpoints.

4

Generate URL

Use SDK methods like getSignedUrl() or generate_presigned_url() with your desired expiration time.

Code Examples πŸ’»

Download (GET) - Node.js

Generate a presigned URL to allow temporary downloads of a private object:

JavaScript
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');

const client = new S3Client({
  endpoint: 'https://s3.us-west-004.backblazeb2.com',
  region: 'us-west-004',
  credentials: {
    accessKeyId: process.env.B2_KEY_ID,
    secretAccessKey: process.env.B2_KEY,
  },
});

const command = new GetObjectCommand({
  Bucket: 'my-bucket',
  Key: 'private/path/secret.pdf'
});

(async () => {
  const url = await getSignedUrl(client, command, { expiresIn: 3600 });
  console.log('Presigned URL:', url);
})();

Download (GET) - Python

Using boto3 to generate presigned URLs with Backblaze:

Python
import boto3
from botocore.client import Config

# Initialize S3 client with Backblaze endpoint
s3_client = boto3.client(
    's3',
    endpoint_url='https://s3.us-west-004.backblazeb2.com',
    aws_access_key_id=os.environ['B2_KEY_ID'],
    aws_secret_access_key=os.environ['B2_KEY'],
    config=Config(signature_version='s3v4'),
    region_name='us-west-004'
)

# Generate presigned URL (valid for 1 hour)
presigned_url = s3_client.generate_presigned_url(
    'get_object',
    Params={'Bucket': 'my-bucket', 'Key': 'private/path/secret.pdf'},
    ExpiresIn=3600
)
print(f'Presigned URL: {presigned_url}')

Upload (PUT) - Node.js

Allow users to upload files directly to Backblaze without exposing credentials:

JavaScript
const { PutObjectCommand } = require('@aws-sdk/client-s3');

const uploadCommand = new PutObjectCommand({
  Bucket: 'my-bucket',
  Key: 'uploads/new-file.pdf',
  ContentType: 'application/pdf'
});

const uploadUrl = await getSignedUrl(client, uploadCommand, {
  expiresIn: 1800  // 30 minutes
});

// Frontend: Use the URL to upload
const response = await fetch(uploadUrl, {
  method: 'PUT',
  body: fileData,
  headers: { 'Content-Type': 'application/pdf' }
});

The Stadium Analogy ⚽

⚽

Newcastle 2-1 Man City (November 2025)

Imagine how presigned URLs work using this epic upset as an analogy...

🏟️

The Stadium = Storage Bucket

Private and secure. Only those with valid tickets (presigned URLs) can enter.

🎫

The Ticket = Presigned URL

Cryptographically signed by the club (API), valid for one match (object) and time window.

πŸ”

Gate Security = Backblaze API

Validates signature and expiry time. No credentials needed at the gate!

⏰

Final Whistle = Expiration

After expiry, even valid tickets can't grant re-entry. Access is revoked automatically.

The Upset: During Newcastle's stunning 2-1 victory, only fans with properly signed tickets saw Barnes score both goals. After the match ended (URL expired), even Haaland with an old season pass (expired/invalid presigned URL) couldn't get back in! 🎯

Backblaze vs AWS S3 πŸ“Š

FeatureBackblaze B2AWS S3
Presigned URL Supportβœ… Full support (GET, PUT, DELETE)βœ… Full SDK support
Storage Cost (per GB)$0.006/GB$0.023/GB (Standard)
Egress/BandwidthFree with Bandwidth Alliance$0.09/GB
API CompatibilityS3-Compatible (endpoint change only)Native AWS SDK
Setup Complexity5 minutes (change endpoint)Standard AWS setup
Max URL Expiry7 days7 days

Security Best Practices πŸ”’

⏰

Minimize Expiration Time

Critical

Use the shortest expiry that works for your use case. For downloads: 5-60 minutes. For uploads: 15-30 minutes.

πŸ”

Always Use HTTPS

Critical

Never use HTTP for presigned URLs. The signature protects tampering, but HTTPS protects the URL itself in transit.

πŸ“

Validate Uploads

High

For PUT presigned URLs, validate content type, file size, and scan for malware. Add Content-Type restrictions.

🚫

Never Expose Keys

Critical

Generate presigned URLs server-side only. Never put API keys in frontend code or client applications.

πŸ“Š

Monitor Usage

Medium

Log presigned URL generation and usage. Set up alerts for unusual patterns or excessive requests.

πŸ”„

Rotate Credentials

High

Regularly rotate your Backblaze application keys. Old URLs will stop working, enhancing security.

Advanced Use Cases 🎯

πŸ“± Direct Mobile Uploads

Mobile apps can request presigned PUT URLs from your backend, then upload directly to Backblaze without proxying through your servers. This saves bandwidth and reduces latency.

Backend β†’ Generate PUT URL β†’ Send to Mobile β†’ Mobile uploads directly to B2

πŸ“§ Secure Email Attachments

Instead of attaching large files to emails, generate short-lived presigned URLs (1-7 days) and share the link. Recipients can download without authentication.

Store file β†’ Generate URL (7 days) β†’ Email link β†’ Recipient downloads

πŸŽ₯ Video Streaming

Generate presigned URLs for video content with appropriate expiry. Video players can stream directly from Backblaze with byte-range requests supported.

User requests video β†’ Generate URL β†’ HLS/MP4 streams from B2 β†’ Expires after viewing

πŸ“Š Report Generation

Generate reports server-side, upload to Backblaze, create a presigned URL, and share with stakeholders. Reports auto-expire after a set period.

Cron job β†’ Generate PDF β†’ Upload to B2 β†’ Create URL (24h) β†’ Notify users

Troubleshooting Guide πŸ”§

SignatureDoesNotMatch Error

Verify your endpoint URL, region, access key ID, and secret key are correct. Ensure no extra whitespace in credentials.

Double-check: endpoint, region, credentials

URL Expired / AccessDenied

The presigned URL has expired or was generated with incorrect permissions. Generate a new URL with appropriate expiry time.

Check: Date/time sync, expiry duration

CORS Errors on Frontend

Configure CORS rules in your Backblaze bucket settings to allow your domain. Include appropriate headers for GET/PUT operations.

Set CORS: AllowedOrigins, AllowedMethods, AllowedHeaders

Upload Fails Silently

Ensure Content-Type header matches what was specified in PutObjectCommand. Verify file size doesn't exceed limits.

Match Content-Type in presigned URL and upload request

Private Bucket Shows Public

Backblaze presigned URLs only work on private buckets. Public buckets don't need presigned URLsβ€”use direct links instead.

Check bucket settings: must be Private

Performance Optimization ⚑

πŸš€

Cache URLs Wisely

If serving the same file to multiple users, generate one presigned URL and cache it on your backend until it's close to expiry.

⚑ Reduces API calls by 90%
🌍

Use CDN Edge Caching

Combine presigned URLs with CloudFlare or other CDNs. Set appropriate Cache-Control headers for frequently accessed files.

⚑ Faster global delivery
πŸ“¦

Batch URL Generation

When displaying lists of files, generate presigned URLs in batch operations rather than one-by-one to reduce round-trip time.

⚑ Parallel processing
⏲️

Lazy Generate URLs

Don't generate presigned URLs until user initiates action. Generate on-demand when download/upload button is clicked.

⚑ Saves unused generations

Real Cost Savings Example πŸ’°

Scenario: Video Platform

10TB storage, 50TB bandwidth per month

AWS S3
$4,730
/month
Storage (10TB):$230
Bandwidth (50TB):$4,500
SAVE 98%
Backblaze B2
$60
/month
Storage (10TB):$60
Bandwidth (50TB):$0*
*Free with Bandwidth Alliance partners
Annual Savings: $56,040

Enough to hire another developer or invest in growth!

Ready to Get Started? πŸš€

Presigned URLs are a powerful tool for secure, scalable file access in cloud storage. With Backblaze's S3-Compatible API, you get enterprise-grade security and performance at a fraction of AWS costs. Whether you're building a file-sharing platform, mobile app, or video streaming service, presigned URLs provide the perfect balance of security, convenience, and cost-effectiveness.

References & Further Reading πŸ“š

Last updated: November 2025 | Built with Next.js & Tailwind CSS

Advertisement