Why signed URLs beat unguessable ones for anything private

29 August 2026

The cheapest way to make a file private is to make its URL hard to guess. Give it enough random characters, do not link to it anywhere, and the only people who can read it are the people you gave it to.

This works better than it deserves to, and it is genuinely the right answer for some things. It is the wrong answer for anything you would mind seeing on someone else's screen, and the reason is not the guessing.

An unguessable URL is a password that cannot be changed

Once handed out, the URL is the credential, and it behaves like one, except:

logs, browser history, and the address bar during a screenshare.

file to build a preview. Your private document is now in somebody's cache.

breaks it for everyone else who has the link.

open it.

  • It travels in the open. URLs land in referrer headers, server logs, proxy
  • Chat apps fetch it. Paste it into Slack or WhatsApp and a bot fetches the
  • It cannot be revoked. Not without deleting the file or moving it, which
  • It never expires. The contractor you sent an invoice to in 2023 can still

None of that is a failure of randomness. Sixty-two to the eighth power is a lot of guesses. The problem is that the secret and the address are the same string, so every place the address goes, the secret goes.

What signing changes

A signed URL splits the two. The address stays the same, and permission becomes a separate, expiring piece of it:

https://filemon.io/api/m1o900k8Zt8fLm3v?exp=1756742400&sig=9f2c...

The signature is an HMAC over the file and the expiry, made with a secret only the service holds. It recomputes it and compares. Nothing is stored, so there is no table of tokens to clean up, and the link stops working at exp whether or not anyone noticed it leaked.

Now the leaks above are survivable. The referrer header carries a URL that dies in an hour. The chat preview bot fetched something that is already stale. The contractor from 2023 holds a link that stopped working the same week.

Getting one

Only whoever holds the key can make a link. On Filemon that is one request with your API key, and the service does the signing, so there is no HMAC to get right and no secret to keep in step:

curl -H "Authorization: Bearer $FILEMON_KEY" \
  "https://filemon.io/api/m1o900r4Nv82PqLd/link?expires=3600"

{
  "url": "https://filemon.io/api/m1o900r4Nv82PqLd?exp=1756742400&sig=9f2c...",
  "expires": "2026-09-01T16:00:00.000Z"
}

Put the url in the email, the image tag or the download button. Anyone holding it can read the file until it expires, and nobody without it can, including someone who knows the id.

The expiry is rounded up to the hour. A signed URL that is unique per request is uncacheable by definition, so a popular file would become one origin hit per view; rounded, everyone who asks within the same hour gets the same URL, and a CDN can do its job.

The one that answers 404

A last detail worth insisting on: when the signature is missing or wrong, a private file should answer 404, not 401. A 401 says "this exists, you just cannot have it", which tells a stranger their guess landed. A 404 tells them nothing at all.

Try it on your own files

Filemon resizes and converts on upload, so the URL you get back is already the finished file. The free plan needs no card.

Create an account · Read the documentation