Skip to main content
View as Markdown

Download URLs

A download signed URL grants read access to exactly one stored path until a moment you choose. Mint it with a session; use it without one.

POST /api/buckets/documents/sign
Content-Type: application/json
Cookie: <session>

{
  "path": "9f3c1e2a-7b44-4d10-9e21-8a6f0c1d2e3b-contract.pdf",
  "expiresIn": 3600
}
{
  "success": true,
  "signedUrl": "https://app.example.com/api/buckets/documents/signed?path=9f3c1e2a-…-contract.pdf&op=download&expires=1775386800000&token=4b1f…",
  "expiresAt": "2026-04-05T11:00:00Z",
  "operation": "download"
}

operation defaults to download, so the field is omitted above. Hand signedUrl to a browser, an email template, or a PDF renderer — it needs nothing else.

Request Body

Field Type Required Default Notes
path string Yes The storage key, exactly as the upload returned it.
expiresIn integer No 3600 Lifetime in seconds. Between 60 and 604800 (7 days).
operation string No download download or upload. See Upload Signing.

Outcomes

Situation Result
Valid request 200 with signedUrl and expiresAt.
expiresIn below 60 or above 604800 400
path missing or empty 400
No file at path 404 — a download token must reference real bytes
No session 401
Session lacking the bucket's sign permission 404
Unknown bucket 404

Note the existence check. Unlike upload signing, download signing refuses to mint a token for a path that holds nothing, so a signed URL you are holding is a URL that resolved at least once.

Using and Expiring the URL

The URL resolves against GET /api/buckets/{bucket}/signed. Three things can go wrong at that point, and all three answer 403:

At use time Result
Within the window, signature intact 200 with the bytes.
Past expiresAt 403
Any query parameter altered — path, expiry, op 403 (signature mismatch)
An upload token used for a GET 403 (operation mismatch)
Token valid but the file was deleted meanwhile 404

Tokens are compared in constant time, so a malformed or near-miss token leaks nothing through response timing. The 403 for expiry and the 403 for tampering are deliberately the same answer.

Transforms on a Signed URL

An image signed URL accepts transform parameters appended to it. The token covers path, op and expires — not the transform query — so one signed URL serves any size:

<signedUrl>&width=200&fit=cover

Raster images arrive with Content-Disposition: inline on this route, so they render directly in an <img>. SVG does not: it is forced to attachment because an inline SVG on your origin can execute script. See Upload Security.

Last updated July 27, 2026

This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta — contributions and corrections are welcome.

Built with Sovrium