Secure Every Image with Signed URLs

HMAC SHA-256 signed URLs prevent unauthorised transformations, hotlinking, and bandwidth abuse. Add expiration timestamps for time-limited access. Constant-time verification stops timing attacks.

Why Sign URLs?

🛡️

Prevent Abuse

Without signing, anyone can request arbitrary transformations — running up your compute bill with width/10000 requests.

🔗

Stop Hotlinking

Only URLs generated by your application are valid. Third-party sites can't embed your images without permission.

⏱️

Expiring Access

Add a Unix timestamp to make URLs valid for a limited time — perfect for user-uploaded content or premium access.

🔒

Timing-Safe

Constant-time comparison (crypto.timingSafeEqual) prevents attackers from guessing tokens character by character.

How It Works

Token = hex(HMAC-SHA256(secret, path))
URL   = path + "?token=" + token

# With expiration:
Token = hex(HMAC-SHA256(secret, path + "?expires=" + timestamp))
URL   = path + "?expires=" + timestamp + "&token=" + token

Setup

Add a secret to any source — that's it:

# sources.yml
my-images:
  type: s3
  bucket: my-bucket
  region: us-east-1
  secret: "a1b2c3d4e5f6...32-char-random-secret"

Sources without a secret remain open. Signing is opt-in per source.

Code Examples

# Node.js
const crypto = require('crypto');
const token = crypto.createHmac('sha256', secret).update(path).digest('hex');
const signedUrl = path + '?token=' + token;

# Python
import hmac, hashlib
token = hmac.new(secret.encode(), path.encode(), hashlib.sha256).hexdigest()

# PHP
$token = hash_hmac('sha256', $path, $secret);

# Ruby
token = OpenSSL::HMAC.hexdigest('sha256', secret, path)

# Go
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(path))
token := hex.EncodeToString(mac.Sum(nil))

Compatible Token Names

Image Foundry accepts tokens via three query parameter names for cross-provider compatibility:

ParameterCompatible With
?token=Image Foundry native
?bossToken=ImageBoss format
?s=Imgix format

Secure Your Images in 5 Minutes

Add a secret to your source config. Generate tokens server-side. Done.

Get Started Free Read the Docs