Downloading videos with signed URLs

Hi everybody!

I’d like to offer downloadable files for my audience. All my videos are using signed URLs.

The docs explain I need to create a token to download the video but I consistently get 401s or 403 responses.

I think I need a $KEYID but I’m unsure what that actually is. The docs say add this as a payload:

    "sub": $VIDEOID,
    "kid": $KEYID, // <- what is this? 
    "exp": 1537460365, 
    "nbf": 1537453165,
    "downloadable": true,

Regardless, I can make tokens it seems.

How would I go about generating a token’d URL to download the video?

I’m using Python so my code looks like this right now:

VIDEOID = 'xxxxxxxxxxxx'
headers = {
    "X-Auth-Email": settings.CLOUDFLARE_API_EMAIL,
    "X-Auth-Key": settings.CLOUDFLARE_API_KEY,
    "Content-Type": "application/json",
data = {
    "sub": VIDEOID,
    "kid": token_id,  # Generated from the /token endpoint with "id", "pem", "exp", and "downloadable: true"
    "id": settings.CLOUDFLARE_SIGNING_TOKEN,
    "pem": settings.CLOUDFLARE_SIGNING_PEM,
    "exp": one_hour,
response =

response = response.json()

It gives me the download URL in the response JSON, but when I click it it returns a 401 unauthorized.

I’m obviously doing something wrong but can’t figure out exactly what I’m doing wrong. The docs leave me hanging a bit here.

Any help would be appreciated!

Info on enabling Downloads for Stream Videos can be found here:

I’ve read that page about 50 times and it doesn’t answer my questions about signed URLs.

I have:

  1. Created a token
  2. Used that token
  3. Get the download URL
  4. GET STUCK because the download URL returns a consistent 401.

I’m successfully using the rest of the Stream API and I know my keys are correct. I just can’t get signed URLs to work with the /downloads endpoint.

Hey! Happy to help @kalob!

First of all, for those reading this in the future, you don’t need signed tokens to download videos if you don’t have require signed urls set for the video. You can just access downloadable videos at$VIDEOID/downloads/default.mp4.

To answer your question, @kalob, it looks like you are conflating the two ways to get a signed token. If you are using the /token endpoint with "id", "pem", "exp", etc; then the output from that request is the token you’re looking for! You can get the output of that API call and use it in place of a video id like this:$TOKEN/downloads/default.mp4

Real world example:`

A URL that looks like this will allow you to download a video.

There is a second way of getting the same result without making a request to the /token endpoint. This is useful if you create more than 10000 tokens a day, for example for each user when they want to watch a video on your site.

This second method allows you to make your own token instead of getting it from the Stream API. You can make your own signed token by getting a $KEYID from the creation of a signing key (link to api docs). Then, you can use the details from the signing key to make your own signing token using one of the libraries at This way, you can generate a token entirely on your own code without having to talk to the Stream API at all.

Hope this helps! Happy to explain more if there is a part that is unclear.

1 Like

Hi @renan

Thank you so much, this helped! I might have just been over thinking this. With your help I got this figured out and working!

  • Kalob

Awesome! Great to hear!

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.