Signed URLs
Signing on img.brandcenter.io follows the Uploadcare/imgix posture:
optional by default. What a signature buys is durability, not access:
| URL | Renders? | Persisted at origin? |
|---|---|---|
w: / p: (any) | ✓ | Already pre-generated |
Unsigned c: / fx: | ✓ — CDN-cached | ✗ ephemeral tier |
Validly signed c: / fx: | ✓ | ✓ durable tier |
| Present-but-invalid signature | ✗ rejected | — |
So you can always paste a crop or effect URL into a browser and tweak it — development stays friction-free. The CMS plugins (Sanity, Payload) derive unsigned URLs by design — they run in browsers, where signing keys never live, and unsigned URLs render forever on the ephemeral tier. Signing is the server-side upgrade for URLs whose renders should be persisted, not re-renderable — apply it where a backend mints or post-processes stored URLs.
The signature op
Section titled “The signature op”s:{kid}:{hmac} is always the last op. The HMAC is SHA-256 over the
canonical path — the full pathname with the ,s:{kid}:{hmac} op removed:
payload: /i/nova/FILE/REV/c:0.250000:0.250000:0.500000:0.500000,w:800.webpsigned: /i/nova/FILE/REV/c:0.250000:0.250000:0.500000:0.500000,w:800,s:1:9ff297….webpkid identifies the signing key, so keys rotate without invalidating URLs
signed with the previous key.
Minting signatures
Section titled “Minting signatures”Signing keys never ship to browsers — signatures are minted server-side. Inside Brandcenter’s stack that is one call:
let signed = await BcImageUrl.signIPath(path, ~kid, ~secret)For your own backend, it’s standard HMAC-SHA256: hex-encode
HMAC_SHA256(secret, canonicalPath) and append ,s:{kid}:{hex} before the
extension. A tampered or wrong-key signature is always rejected — tampering
never silently degrades to “unsigned”.