Download OpenAPI specification:
This document covers the Alibaba implementation of CacheFly Signed URLs v2 only. Support for additional algorithms (CDN77, Bunny, Cloudflare, Searchbots, etc.) is coming soon; their v2 documentation will be published as they become available.
Signed URLs restrict access to content by validating a signature contained in the request URL (path or query) before origin fetch. v2 introduces a structured configuration with a default policy, per-path exceptions, and a fallback mechanism.
The v2 configuration file can be provided as YAML or JSON. The top-level structure contains a single default protection and a list of exceptions that can override it for matching requests.
---
default: # Required. The default protection applied to all requests.
# ... a protection object (see below)
exceptions: # Required. Per-path overrides.
- path: "/private" # Request path must start with this (default "/")
pathFilter: ["*"] # Optional wildcard patterns to match the rest of the path
extensions: ["*"] # Optional file extensions to match
# The protection applied when this exception matches
algorithm: "alibaba"
secret: "<shared secret>"
type: "a"
# ... other Alibaba options
A protection selects and configures the algorithm enforced for a given scope. All protections support:
Rollout status (v2): alibaba (available in this document); cdn77, bunny-basic, cloudflare, searchbots (coming soon). Generic allow/deny exist but are outside the scope of this document.
At request time, the CDN evaluates the configuration as follows:
default protection.path, then pathFilter/extensions) and adopt its protection if found.fallback is configured, recursively apply the fallback.denyCode (default 403).If your protection rewrites the request (e.g., removes signing tokens), the rewritten path is used for the remainder of the request lifecycle.
This algorithm implements the Alibaba Cloud CDN URL Signing types, with some configurable extensions.
alibabasecrettype: One of a, b, c, c1, c2, f, f1, f2, or auto (default auto).ttl: Integer seconds (default 1800) added to the provided timestamp to determine expiry.hash: One of md5, sha1, sha256, sha384, sha512 (default md5).rewritePath: Boolean (default true) — if true, the request URI is rewritten to remove signing bits after verification.signField: Query parameter name holding the signature (types C2/F2; defaults per type).timeField: Query parameter name holding the timestamp (types C2/F2; defaults per type).utcOffset: Integer hours offset applied to current time when evaluating expiry. Defaults per type (notably type B defaults to 8).pathFormat: For path-based types: TS/SIG or SIG/TS (defaults per type).timeFormat: One of decimal, hex, yyyyMMddHHmm (defaults per type).signatureFormat: Internal signature template, see Signature construction below (defaults per type).The secret must be 6–128 characters.
Type A (query): ?auth_key=<timestamp>-<rand>-<uid>-<md5hex>
signField=auth_key, timeFormat=decimal, utcOffset=0, signatureFormat=[P]-[T]-[R]-[I]-[S].Type B (path): /<timestamp>/<md5hex>/path
pathFormat=TS/SIG, timeFormat=yyyyMMddHHmm, utcOffset=8, signatureFormat=[S][T][P].Type C (path or query):
/<md5hex>/<hex_ts>/path?KEY1=<md5hex>&KEY2=<hex_ts>signField=KEY1, timeField=KEY2, timeFormat=hex, pathFormat=SIG/TS, utcOffset=0, signatureFormat=[S][P][T].Type F (path or query):
/<md5hex>/<hex_ts>/path?sign=<md5hex>&time=<hex_ts>signField=sign, timeField=time, timeFormat=hex, pathFormat=SIG/TS, utcOffset=0, signatureFormat=[S][P][T].Type auto: Detects signing type from the request:
auth_key → A, KEY1 → C, sign → F./12-digit-ts/32-hex/ → B, /32-hex/8-hex/ → C (preferred over F when ambiguous).If detection fails, the request is denied.
decimal: 10-digit Unix time (seconds).hex: 8 hex digits representing Unix time (seconds).yyyyMMddHHmm: 12-digit UTC clock representation (year, month, day, hour, minute). For type B, evaluation is performed relative to utcOffset (defaults to +8 hours).Expiry check: parsed_timestamp + ttl >= now_with_offset must hold. Otherwise the request is denied.
The algorithm constructs a string and applies the configured hash:
S: secretT: timestamp (string form exactly as in the URL)P: path (request URI without query)Q: full request URI including query (after removing signing fields)E: URL-encoded request URI including query (after removing signing fields)I: user id (Type A)R: nonce/random (Type A)Default signatureFormat per type:
[P]-[T]-[R]-[I]-[S][S][T][P][S][P][T]The output is the lowercase hexadecimal digest for the selected hash.
If rewritePath: true (default):
/<ts>/<sig>/ (or /<sig>/<ts>/) prefix is stripped from the request before origin fetch.Disable this only if your origin requires the signing bits.
---
default:
algorithm: deny
exceptions:
- path: "/video"
algorithm: alibaba
secret: "your-secret-here"
type: a
ttl: 1800
hash: md5
# rewritePath: true # default
Example request:
/video/file.mp4?auth_key=<ts>-<rand>-<uid>-<md5hex>
---
default:
algorithm: deny
exceptions:
- path: "/downloads"
algorithm: alibaba
secret: "your-secret-here"
type: b
ttl: 900
# timeFormat defaults to yyyyMMddHHmm; utcOffset defaults to 8
Example request (default TS/SIG):
/downloads/202503141230/0123456789abcdef0123456789abcdef/path/to/file.mp4
---
default:
algorithm: deny
exceptions:
# C1: path variant
- path: "/assets"
algorithm: alibaba
secret: "your-secret-here"
type: c1
# pathFormat defaults to SIG/TS; timeFormat defaults to hex
# C2: query variant
- path: "/public"
algorithm: alibaba
secret: "your-secret-here"
type: c2
signField: KEY1 # default
timeField: KEY2 # default
Examples:
# C1 path
/assets/0123456789abcdef0123456789abcdef/5f5e1000/file.jpg
# C2 query
/public/file.jpg?KEY1=0123456789abcdef0123456789abcdef&KEY2=5f5e1000
default:
algorithm: deny
exceptions:
- path: "/media"
algorithm: alibaba
secret: "your-secret-here"
type: f2
signField: sign # default
timeField: time # default
# signatureFormat: "[S][Q][T]" # optional variant if needed
Examples:
# F1 path
/media/0123456789abcdef0123456789abcdef/5f5e1000/clip.mp4
# F2 query
/media/clip.mp4?sign=0123456789abcdef0123456789abcdef&time=5f5e1000
Below are minimal PHP reference implementations matching the defaults. Adjust hash to your chosen algorithm.
function alibaba_type_a_sign(string $url, string $secret, string $uid = '0', ?string $rand = null, ?int $ts = null, string $hash = 'md5'): string {
$parts = parse_url($url);
$path = $parts['path'] ?? '/';
$ts = $ts ?? time();
$rand = $rand ?? bin2hex(random_bytes(4));
$internal = $path . '-' . $ts . '-' . $rand . '-' . $uid . '-' . $secret;
$signature = match ($hash) {
'md5' => md5($internal, false),
'sha1' => sha1($internal, false),
'sha256', 'sha384', 'sha512' => hash($hash, $internal, false),
default => md5($internal, false)
};
$token = $ts . '-' . $rand . '-' . $uid . '-' . $signature;
$query = [];
if (!empty($parts['query'])) { parse_str($parts['query'], $query); }
$query['auth_key'] = $token;
$query_str = http_build_query($query);
return ($parts['scheme'] ?? 'https') . '://' . ($parts['host'] ?? '') . $path . ($query_str ? ('?' . $query_str) : '');
}
function alibaba_type_b_path(string $base, string $path, string $secret, string $hash = 'md5', int $utcOffset = 8): string {
$path = '/' . ltrim($path, '/');
$ts = gmdate('YmdHi', time() + ($utcOffset * 3600)); // yyyyMMddHHmm in UTC+offset
$internal = $secret . $ts . $path; // [S][T][P]
$signature = match ($hash) {
'md5' => md5($internal, false),
'sha1' => sha1($internal, false),
'sha256', 'sha384', 'sha512' => hash($hash, $internal, false),
default => md5($internal, false)
};
return rtrim($base, '/') . '/' . $ts . '/' . $signature . $path; // TS/SIG
}
function alibaba_type_cf_query(string $url, string $secret, string $signField = 'KEY1', string $timeField = 'KEY2', string $hash = 'md5', ?int $ts = null): string {
$parts = parse_url($url);
$path = $parts['path'] ?? '/';
$ts = $ts ?? time();
$hexTs = str_pad(dechex($ts), 8, '0', STR_PAD_LEFT);
$internal = $secret . $path . $hexTs; // [S][P][T]
$signature = match ($hash) {
'md5' => md5($internal, false),
'sha1' => sha1($internal, false),
'sha256', 'sha384', 'sha512' => hash($hash, $internal, false),
default => md5($internal, false)
};
$query = [];
if (!empty($parts['query'])) { parse_str($parts['query'], $query); }
$query[$signField] = $signature;
$query[$timeField] = $hexTs;
$query_str = http_build_query($query);
return ($parts['scheme'] ?? 'https') . '://' . ($parts['host'] ?? '') . $path . ($query_str ? ('?' . $query_str) : '');
}
function alibaba_type_cf_path(string $base, string $path, string $secret, string $hash = 'md5', string $pathFormat = 'SIG/TS'): string {
$path = '/' . ltrim($path, '/');
$ts = time();
$hexTs = str_pad(dechex($ts), 8, '0', STR_PAD_LEFT);
$internal = $secret . $path . $hexTs; // [S][P][T]
$signature = match ($hash) {
'md5' => md5($internal, false),
'sha1' => sha1($internal, false),
'sha256', 'sha384', 'sha512' => hash($hash, $internal, false),
default => md5($internal, false)
};
$base = rtrim($base, '/');
if ($pathFormat === 'TS/SIG') {
return $base . '/' . $hexTs . '/' . $signature . $path;
}
// Default SIG/TS
return $base . '/' . $signature . '/' . $hexTs . $path;
}
secret length is between 6 and 128 characters.timeFormat./<ts>/<sig>/ (or /<sig>/<ts>/) prefix.type: auto, confirm that your URL layout matches the detection heuristics.