Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tenbyte.io/llms.txt

Use this file to discover all available pages before exploring further.

Token authentication protects content with time-limited signed URLs. Each URL carries an MD5-based token plus an expiry timestamp; the CDN edge validates both before serving the file. Links expire on schedule and cannot be tampered with — the secret never leaves your server. Use it for HLS / DASH streams, private downloads, embedded video players, and any media you want gated behind your application’s auth.

Request flow

The secret stays on your server. Clients only ever see the finished signed URL.

Enable token authentication

Token Authentication
  1. Open CDNDistributions → select your distribution.
  2. Go to Access RulesAdd Access Rules (or open an existing rule).
  3. Set the Match Pattern to the path you want to protect (for example /videos/*).
  4. Toggle Token Authentication on.
  5. Click Generate Token to mint a Secret Token, then Copy Token.
  6. Click Create Access Rules to save.
Token authentication is configured per access rule, not globally. Each rule has its own secret, so you can scope tokens to a path prefix and rotate them independently.
Treat the secret like a database password. Store it in your secret manager (AWS Secrets Manager, GCP Secret Manager, Vault, Doppler, etc.), inject it via environment variable, and never commit it to a repo or expose it in client-side code.

URL anatomy

https://<distribution>.tenbytecdn.com/<path>?md5=<token>&expires=<unix_ts>
PartSourceNotes
<distribution>Your distribution hostnameCan be a custom domain CNAMEd to the distribution.
<path>Path to the assetMust start with /. Must match the access rule’s Match Pattern, otherwise the rule is skipped.
md5Computed tokenURL-safe base64 of the MD5 hash. No +, /, or =.
expiresUnix timestamp (seconds)After this, the edge returns 403.

Signing algorithm

  1. Build the string {expires}{path} {secret} — note the single space before the secret.
  2. MD5 hash with raw binary output (16 bytes), not hex.
  3. Base64-encode the binary hash.
  4. Make the base64 URL-safe: replace +-, /_, strip = padding.
  5. Append ?md5={token}&expires={unix_timestamp} to the CDN URL.

Configuration

Drive everything from environment variables — never hard-code the secret.
.env
TENBYTE_CDN_HOST=https://your-distribution.tenbytecdn.com
TENBYTE_CDN_SECRET=replace-with-secret-from-console
TENBYTE_CDN_TTL=1800
VariableDescriptionExample
TENBYTE_CDN_HOSTDistribution hostname (no trailing slash)https://your-distribution.tenbytecdn.com
TENBYTE_CDN_SECRETSecret token from the access ruleinjected at runtime
TENBYTE_CDN_TTLToken lifetime in seconds1800 (30 min)

Generate signed URLs

Reference implementations live in the tenbyte-cdn-signed-url-example repo. Pick a language, copy the function, swap your config.
<?php
/**
 * @param string $cdnHost  Distribution host, e.g. "https://xxx.tenbytecdn.com"
 * @param string $path     Resource path, must start with "/"
 * @param string $secret   CDN secret token (server-side only)
 * @param int    $ttl      Token lifetime in seconds (default 1800)
 */
function tenbyteSignedUrl(
    string $cdnHost,
    string $path,
    string $secret,
    int $ttl = 1800
): string {
    $expires = time() + $ttl;

    $link = "$expires$path $secret";
    $md5 = md5($link, true);
    $md5 = base64_encode($md5);
    $md5 = strtr($md5, "+/", "-_");
    $md5 = str_replace("=", "", $md5);

    $cdnHost = rtrim($cdnHost, "/");

    return "{$cdnHost}{$path}?md5={$md5}&expires={$expires}";
}

$url = tenbyteSignedUrl(
    getenv("TENBYTE_CDN_HOST"),
    "/videos/sample/index.m3u8",
    getenv("TENBYTE_CDN_SECRET"),
    (int) (getenv("TENBYTE_CDN_TTL") ?: 1800)
);
echo $url, "\n";

Verify with curl

Mint a URL, hit the edge, expect 200:
SIGNED_URL="$(node js/index.js)"   # or php/go/python equivalent
curl -sSI "$SIGNED_URL" | head -1
# HTTP/2 200
Negative tests — both should return 403:
# Tampered path (token won't match)
curl -sSI "${SIGNED_URL/index.m3u8/secret.m3u8}" | head -1

# Expired
curl -sSI "${SIGNED_URL/expires=*/expires=1}" | head -1

Use the URL in a player

The signed URL is a normal HTTPS URL — drop it into any player. For HLS streams, sign the manifest only; segments inherit the rule as long as the Match Pattern covers them.
<video controls src="https://your-distribution.tenbytecdn.com/videos/sample/index.m3u8?md5=...&expires=..."></video>

Operations

Choosing a TTL

WorkloadSuggested TTLWhy
Image / thumbnail60–300 sShort request, easy to re-sign on retry.
Private download5–15 minLong enough for a slow connection, short enough to limit URL sharing.
HLS / DASH live1–4 hMust outlast the session: full playback + ABR switches + pause/resume.
HLS VOD2–6 hShould cover the longest expected viewing session in one URL.
Set TTL ≥ longest possible playback session. If a viewer pauses past the expiry, the next segment fetch returns 403 and the player stalls.

Clock skew

expires is compared against the edge’s wall clock. Servers signing URLs should run NTP. If your sign host drifts ahead, the edge sees a token that is “already expired”; if it drifts behind, tokens live longer than expected. A skew of ±60 seconds is usually invisible — anything more is a config issue.

Rotating the secret

The console only stores one active secret per access rule. Rotation is a hard cutover, so do it at low traffic and keep a short overlap by issuing short-TTL tokens leading up to the swap.
T-1h    Drop new sign-time TTL to 5 min so old tokens age out fast
T-0     Click Regenerate, copy new secret
T-0+s   Push new secret to your secret manager / app config
T-0+m   Restart / reload signing services
T+5m    Old tokens fully expired — back to normal TTL

Multiple environments

Use one access rule per environment with its own secret and a path prefix that namespaces traffic — for example /prod/* and /staging/*. That way a leaked staging secret cannot sign production URLs.

Logging and observability

  • Log the path you signed and expires value, never the secret or the full signed URL — query strings often end up in access logs.
  • Track edge 403 rate per access rule. A spike usually means clock skew, expired tokens, or a bug in your signer.
  • For incident triage, keep the signing function pure (input in, URL out) so you can replay it offline against suspect timestamps.

Security checklist

  • Secret stored in a secret manager, injected via env var.
  • Signing happens only on the server. No browser code, no mobile-client embedded secrets.
  • Per-environment access rules with distinct secrets.
  • TTL is the shortest value your workload tolerates.
  • Rotation runbook documented and tested.
  • Application auth gates the signer endpoint — never let an unauthenticated request mint a URL.
  • Combine with Referrer, IP, or Country policies for defense in depth.

Troubleshooting

ProblemFix
403 Forbidden on a fresh URLPath doesn’t match the rule’s Match Pattern, or your sign host’s clock is ahead of the edge. Check date -u and the rule pattern.
Token works in PHP but not Go / Node / PythonMD5 must be raw binary before base64, not the hex string.
URL contains + or / and breaksApply the URL-safe base64 step (+-, /_).
Trailing = in token causes 403Strip all = padding.
Manifest plays, segments 403Access rule pattern only covers the manifest. Broaden the pattern (e.g. /videos/*) so segment paths match.
Works in curl but not the browserBrowser cached an old manifest. Bust cache or use a fresh signed URL.
Intermittent 403 near expiryTTL too short for the session. Bump TTL or re-sign on player error.