DEV Community

Mobeen Ahmed
Mobeen Ahmed

Posted on

Expiring Signed URLs: Why Some Download Links Die After Minutes

If you have ever pasted a video link into a downloader, got a perfectly good download link, and then come back ten minutes later to find it dead, you have met an expiring signed URL. It is not a bug. It is the CDN doing exactly what it was told to do, and once I understood how it works, it changed how I built my downloader.

What a signed URL actually is

A signed URL is a normal file URL with a few extra query parameters bolted on: an expiry timestamp, and a signature computed from the path, the expiry, and a secret key only the CDN knows. When a request arrives, the CDN checks the signature, then checks the clock. If the timestamp has passed, it returns a 403, even though the file is still sitting there. You cannot just edit the expiry to a later date either — the signature would stop matching, and the request would be rejected anyway.

The idea is simple. A video platform does not want its files to be hotlinked forever. When you watch a video, the platform hands your browser a signed URL that works for a few minutes — long enough to start streaming, short enough that the link is useless once it leaks onto a forum. For streaming that works well. The trouble starts when a tool like mine hands that same link to a person and expects them to click it.

Why this broke my first design

My early version of ramrom.io resolved a pasted link and showed the download button straight away. That worked fine in testing, because I always clicked immediately. Real visitors do not always do that. Someone pastes a link, gets distracted, reads the quality options, or switches apps on their phone. Five or ten minutes pass, they tap download, and the CDN says no. From their side it looks like the tool is broken. From my side, nothing failed at all — the provider did its job, the proxy did its job, and the link was simply dead.

Worse, the failure is confusing. A dead signed URL does not return a helpful message. It returns a 403 or an XML error page, and if the browser treats the response as a file, the visitor ends up with a tiny text file named something like video.mp4 that contains an error. I wrote about checking for that in a previous post: never trust the filename.

What I do about it now

First, I resolve late. I do not fetch the download URL when the visitor pastes the link. I fetch it when they actually tap the quality they want. That shortens the gap between the link being created and the link being used from minutes to seconds. It costs an extra round trip, but it is the single biggest improvement I made to download reliability.

Second, I keep the flow short. The quality list shows the file size next to each option so the visitor can decide in one glance instead of deliberating over three identical-looking entries. Every extra second of thinking is a second closer to expiry.

Third, I do not cache resolved links. It would be tempting — resolve once, serve the same URL to everyone who pastes the same video. But a cached signed URL is a dead URL waiting to happen, and it would also mean one visitor's link being handed to another. So the resolve step runs fresh every time, even if it costs an API call.

Finally, when a download does fail, I say so plainly. If the proxy gets a 403 from the CDN, the visitor sees a message that the link has expired and they can tap again to get a fresh one. A re-tap costs nothing and usually works, because the new resolve call returns a brand new signed URL with a fresh expiry. That is far better than a broken file or a spinner that never ends.

The takeaway

Signed URLs exist because platforms need links that die. If you are building anything that hands a CDN link to a person — a downloader, a file sharing page, a preview tool — design for the expiry. Resolve as late as you can, keep the path from link to download as short as you can, and never cache a URL that has a clock in it. The link is not permanent, and pretending it is will only confuse your visitors.

Top comments (0)