> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gcore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Generate advanced secure tokens for MP4

> Generate advanced secure tokens for MP4 files with signing parameters, expiration, speed limits, and IP binding examples.

MP4 files use a different signing formula from HLS/DASH. The token is passed as a query parameter rather than embedded in the URL path. The formula optionally includes download speed limiting parameters (`speed` and `buffer`).

> [!NOTE]
>
> Advanced MP4 tokens cannot be combined with [video secure tokens for HLS/DASH](/streaming/interaction-with-cdn/video-secure-token). If both are configured on the same CDN resource, the HLS/DASH token takes precedence.

## Protected URL format

```sh theme={null}
https://domain.com/videos/account_id_video_id/filename.mp4?md5={token}&expires={expiration}[&speed={speed}][&buffer={buffer}]
```

Where:

* `{token}` — MD5 hash of the MP4 file path and signing parameters
* `{expiration}` — Unix timestamp (seconds) at which the URL expires
* `&speed={speed}` — optional; download speed limit (e.g. `1M`, `500K`)
* `&buffer={buffer}` — optional; buffer size for rate limiting (e.g. `10M`)

The `speed` and `buffer` query parameters must match the values included in the token signature. Tampering with these values returns 403 Forbidden.

## String to sign

Without IP binding:

```text theme={null}
${uri}_${secret}_${expires}_${speed}_${buffer}_
```

With IP binding:

```text theme={null}
${uri}_${secret}_${expires}_${speed}_${buffer}_${user_ip}
```

| Parameter | Required | Description |
| - | - | - |
| **uri** | yes | Path portion of the MP4 file URL (e.g. `/videos/account_video/filename.mp4`) |
| **secret** | yes | Key from CDN resource **Access** > **Secure token** settings |
| **expires** | yes | Expiration time as a Unix timestamp (UTC) |
| **speed** | optional | Download speed limit in bytes/sec (e.g. `1M`, `500K`). Use an empty string if not required |
| **buffer** | optional | Buffer size for rate limiting (e.g. `10M`). Used together with `speed`; leave empty when `speed` is not set |
| **user\_ip** | IP binding only | Client IP address |

An [MP4 speed limit](/streaming/video-hosting/download-mp4-files#limit-mp4-download-speed) must be configured on the CDN resource for `speed` and `buffer` to take effect.

## Sign examples

The following examples show how different parameter combinations change both the string to sign and the resulting URL.

Secret: `MySecr3tStr1ng`

Without speed limit or IP binding:

```text theme={null}
string to sign: /videos/279481_1053391/qid2920v1_h264_4050_1080_1.mp4_MySecr3tStr1ng_1743167062___
url: http://gvideo.dev/videos/279481_1053391/qid2920v1_h264_4050_1080_1.mp4?md5=QX39c77lbQKvYgMMAvpyMQ&expires=1743167062
```

With speed limit (`1M`), buffer (`10M`), and IP binding (`1.2.3.4`):

```text theme={null}
string to sign: /videos/279481_1053391/qid2920v1_h264_4050_1080_1.mp4_MySecr3tStr1ng_1743167062_1M_10M_1.2.3.4
url: http://gvideo.dev/videos/279481_1053391/qid2920v1_h264_4050_1080_1.mp4?md5=xyRBh7y3LB9ER4Ijr-0hQA&expires=1743167062&speed=1M&buffer=10M
```

## Code examples

**Python**

```python theme={null}
import base64
from hashlib import md5
from time import time

def gethash_mp4(uri, secret, expires, speed, buffer, ip):
    hash_body = "%s_%s_%d_%s_%s_%s" % (uri, secret, expires, speed, buffer, ip)
    hash_md5 = base64.b64encode(
        md5(hash_body.encode()).digest()
    ).decode().replace("+", "-").replace("/", "_").replace("=", "")
    return hash_md5

secret = ""                                                   # enter your key from the CDN resource (Access > Secure token)
uri = "/videos/2675_pG8TfmKx2LU2qs/qid3570v1_h264_1800_720.mp4"

expires = int(time()) + 24 * 60 * 60                          # expiration = now + 24 hours

# MP4 without speed limit (CDN resource: "Add a client's IP to the token" disabled)
token = gethash_mp4(uri, secret, expires, "", "", "")
print(f"https://demo-protected.gvideo.io{uri}?md5={token}&expires={expires}")

# MP4 with speed and buffer limit
speed = "1M"
buffer = "10M"
token = gethash_mp4(uri, secret, expires, speed, buffer, "")
print(f"https://demo-protected.gvideo.io{uri}?md5={token}&expires={expires}&speed={speed}&buffer={buffer}")

# MP4 with IP binding (CDN resource: "Add a client's IP to the token" enabled)
ip = "92.223.112.84"
token = gethash_mp4(uri, secret, expires, "", "", ip)
print(f"https://demo-protected-ip.gvideo.io{uri}?md5={token}&expires={expires}")
```

Python playground – [https://www.onlineide.pro/playground/share/d6126cff-e97f-456b-b667-6a95030563b4](https://www.onlineide.pro/playground/share/d6126cff-e97f-456b-b667-6a95030563b4)

**Go**

```go theme={null}
package main

import (
    "crypto/md5"
    "encoding/base64"
    "fmt"
    "time"
)

func getHashMP4(uri, secret string, expires int64, speed, buffer, ip string) string {
    hashBody := fmt.Sprintf("%s_%s_%d_%s_%s_%s", uri, secret, expires, speed, buffer, ip)
    md5sum := md5.Sum([]byte(hashBody))
    hashMd5 := base64.RawURLEncoding.EncodeToString(md5sum[:])
    return hashMd5
}

func main() {
    var token, speed, buffer string

    secret := ""                                                         // enter your key from the CDN resource (Access > Secure token)
    uri := "/videos/2675_pG8TfmKx2LU2qs/qid3570v1_h264_1800_720.mp4"

    timeNow := time.Now().UTC()
    expires := timeNow.Add(24 * time.Hour).Unix()                       // expiration = now + 24 hours

    // MP4 without speed limit
    token = getHashMP4(uri, secret, expires, "", "", "")
    fmt.Printf("https://demo-protected.gvideo.io%s?md5=%s&expires=%d\n", uri, token, expires)

    // MP4 with speed and buffer limit
    speed = "1M"
    buffer = "10M"
    token = getHashMP4(uri, secret, expires, speed, buffer, "")
    fmt.Printf("https://demo-protected.gvideo.io%s?md5=%s&expires=%d&speed=%s&buffer=%s\n", uri, token, expires, speed, buffer)

    // MP4 with IP binding (CDN resource: "Add a client's IP to the token" enabled)
    ip := "92.223.112.84"
    token = getHashMP4(uri, secret, expires, "", "", ip)
    fmt.Printf("https://demo-protected-ip.gvideo.io%s?md5=%s&expires=%d\n", uri, token, expires)
}
```

Go playground – [https://goplay.tools/snippet/iqktoxSaTh3](https://goplay.tools/snippet/iqktoxSaTh3)
