Download OpenAPI specification:Download
This document describes the configuration format for CacheFly Signed URLs.
Signed URLs provide a way to limit access to premium or private content. By adding a signature into the URL we can enforce your dynamically configured policies, such as expiry and location.
Several different algorithms are supported, with additional algorithms being added on request. Our intent is for our CDN to be able to accomidate the way that you want to sign URLs.
Once Signed URLs are enabled for your account, you will have the option of creating a configuration file. This configuration is then associated with your services. This gives you full control over when signing is enforced.
You may upload the configuration file to the CDN via the API or the Portal.
Please note that this configurable Signed URLs service is a more advance alternative to our own ProtectServe service. If you need simplicy then ProtectServe may be a better choice.
The configuration file for Signed URLs may be provided to us in either YAML or JSON format. We have supported both as a convenience to our customers. We are aware that some customer automations find it easier to work with JSON. Please pay attention to the MIME type while uploading the configuration.
All the configuration examples here are shown in YAML format. YAML is intended to be more human friendly than JSON. It is reasonably easy to follow (without any experience), but sometimes writing it takes a little getting used to. The main advantages of YAML are the lack of curly braces, the use of indentation to define the structure, and the ability to add comments.
If you are not familiar with YAML, there are many great resources online to help you get started.
Additionally a YAML aware IDE or editor will help you with authoring and modifying the configuration file.
The editor within our Portal is based on the well known Visual Studio Code editor, and will show various warnings and errors as you type. You should ensure that all of these are addressed before saving the configuration.
However our Portal is intended to be useful and convenient (we're a CDN, not a fully featured IDE company). As such we also wish to provide you with a list of other tools that our team has found useful;
If you require any support with authoring or modifying your configuration files, please contact our support team who will be very happy to assist.
After uploading your configuration to us, our systems will deploy it to the CDN (almost) immediately.
When applying changes there may, or may not, be a propagation delay. This is to ensure that a high frequency of changes by a small number of users does not negatively impact the performance of the network as a whole. As such, although we endeavour to make this as fast as possible, and immediate in most cases, the only guarantee is that it will occur eventually.
Some limited validation checks are performed during upload. If they fail your new configuration not be applied and the existing configuration will continue to be used. However there are many small details that can not be checked automatically, and it is easy to break an in production system by introducing an error into the configuration.
We recommend that you:
It is possible for us to revert to a previous configuration if you have a problem. However this is a manual process and will take some time to complete.
The Signed URLs configuration file contains a single key called algorithms
, inside of which you list all the
different signing algorithm configurations that you wish to use for your service.
The value of the name
property informs us of which algorithm to use.
The value of the path
property tells us which paths you want to protect
with this configuration.
---
algorithms:
# This is the first configuration for this service
- name: "CLOUDFLARE" # name of the algorithm
path: "/data" # the path being protected
secret: "19GTkGGYKYgL7ZvI" # the secret used for the signatures
# This is the second configuration for this service
- name: "CLOUDFLARE"
path: "/video"
secret: "BC423lkds382X3cc"
{
"algorithms": [
{
"name": "CLOUDFLARE",
"path": "/data",
"secret": "19GTkGGYKYgL7ZvI"
},
{
"name": "CLOUDFLARE",
"path": "/video",
"secret": "BC423lkds382X3cc"
}
]
}
The CDN attempts to match incoming requests to one of the configurations in the list based on the path.
When the signature is found to be invalid or expired, the request is denied and a 403 is returned.
If there is no match, then the request is allowed by default.
If there are multiple matches, only the first is considered.
If you require an algorithm other than those described here please contact our support team. Note the easiest way to do this is to use the Open a ticket option in our customer portal.
This algorithm matches the default Signed URLs algorithm used by Cloudflare.
name
You must specify the name as CLOUDFLARE
.
path
You must specify a path. Use may the value /
to mean all paths.
secret
You must specify the secret used which is during the signing.
queryParamTokenName
This allows you to specify the name of the query parameter which stores the signature.
This defaults to the value mac
.
queryParamExpiryName
The name of the query parameter which contains the expiry date.
This defaults to the value expiry
.
---
algorithms:
# Example Cloudflare style Signed URL
#
# https://example.cachefly.net/data/file/video.mp4?mac=29QpicPWKD6RpuYMfC8LfA==&expiry=1389183132
#
- name: "CLOUDFLARE" # name of the algorithm
path: "/data" # the path being protected
secret: "19GTkGGYKYgL7ZvI" # the secret used for the signatures
queryParamTokenName: "mac" # optional: query parameter name containing the signature
queryParamExpiryName: "expiry" # optional: query parameter name containing an expiry timestamp
The following example shows how to generate the signature using Python 3:
import hashlib
import hmac
import base64
from urllib.parse import urlparse, urlunparse, urlencode
def generate_signed_url(url, secret_key, expiry):
# Create the data to be authenticated
data_to_authenticate = urlparse(url).path + "@" + str(expiry)
# Calculate the HMAC hash for the data
mac = hmac.new(secret_key.encode(), data_to_authenticate.encode(), hashlib.sha256).digest()
encoded_mac = base64.b64encode(mac).decode()
# Append the query parameters to the URL
parsed_url = urlparse(url)
query_params = {'mac': encoded_mac, 'expiry': expiry}
updated_query = urlencode(query_params)
signed_url = urlunparse((parsed_url.scheme, parsed_url.netloc, parsed_url.path, parsed_url.params, updated_query, parsed_url.fragment))
return signed_url
# Example usage:
original_url = "https://example.com/verify/path/to/resource"
secret_key = "my secret symmetric key"
expiry = int(time()) + 3600 # Set the URL expiration to one hour from now
signed_url = generate_signed_url(original_url, secret_key, expiry)
print("Signed URL:", signed_url)
The following example shows how to generate the signature using PHP:
function generateSignedUrl(string $url, string $secretKey, int $expiry): string
{
// Create the data to be authenticated
$dataToAuthenticate = parse_url($url, PHP_URL_PATH) . "@" . $expiry;
// Calculate the HMAC hash for the data
$mac = hash_hmac("sha256", $dataToAuthenticate, $secretKey, true);
$encodedMac = base64_encode($mac);
// Append the query parameters to the URL
$parsedUrl = parse_url($url);
$parsedUrl['query'] = http_build_query(['mac' => $encodedMac, 'expiry' => $expiry]);
// Rebuild the URL with the updated query parameters
$signedUrl = $parsedUrl['scheme'] . '://' . $parsedUrl['host'] . $parsedUrl['path'] . '?' . $parsedUrl['query'];
return $signedUrl;
}
// Example usage:
$originalUrl = "https://example.com/verify/path/to/resource";
$secretKey = "my secret symmetric key";
$expiry = time() + 3600; // Set the URL expiration to one hour from now
$signedUrl = generateSignedUrl($originalUrl, $secretKey, $expiry);
echo "Signed URL: " . $signedUrl;
This algorithm matches the CDN77 secure token functionality by default. Additionally options are provided for being able to pass signature and expiry date via cookies.
name
You must specify the name as CDN77
.
path
You must specify a path. Use may the value /
to mean all paths.
type
You must specify a type, which informs us where to find the signature.
The supported types are:
type | description |
---|---|
QUERY |
Signature is in query parameter(s) |
PATH |
Signature is in the path |
COOKIE |
Signature is in a cookie |
secret
You must specify the secret used which is during the signing.
queryParamName
Only used when the type
property is set to QUERY
.
This allows you to specify the name of the query parameter which stores the signature.
This defaults to the value secure
.
cookieTokenField
Only used when the type
property is set to COOKIE
.
This allows you to specify the name of the cookie which stores the signature.
Note that cookie names are always case sensitive.
This defaults to the value token
.
cookieExpiryField
Only used when the type
property is set to COOKIE
.
This allows you to specify the name of the cookie which stores an expiry date.
Note that cookie names are always case sensitive.
This defaults to the value expiry
.
---
algorithms:
# Example CDN77 style secure token using query parameter
#
# https://example.cachefly.net/private/video.mp4?secure=29QpicPWKD6RpuYMfC8LfA==,1389183132
#
- name: "CDN77" # name of the algorithm
path: "/private" # the path being protected
type: "QUERY" # the implementation type
secret: "19GTkGGYKYgL7ZvI" # the secret used for the signatures
queryParamName: "secure" # optional: query parameter name containing the signature
# Example CDN77 style secure token using path
#
# https://example.cachefly.net/z--FA_CsNsR2TOV2eg9q4w==,1389183132/downloads/video.mp4
#
- name: "CDN77" # name of the algorithm
path: "/downloads" # the path being protected
type: "PATH" # the implementation type
secret: "19GTkGGYKYgL7ZvI" # the secret used for the signatures
# Example CDN77 style secure token using cookies
#
# https://example.cachefly.net/video/playlist/d.m3u8
#
# COOKIES:
# - token=29QpicPWKD6RpuYMfC8LfA==
# - expiry=1389183132
#
- name: "CDN77" # name of the algorithm
path: "/video" # the path being protected
type: "COOKIE" # the implementation type
secret: "19GTkGGYKYgL7ZvI" # the secret used for the signatures
cookieTokenField: "token" # optional: cookie name containing the signature
cookieExpiryField: "expiry" # optional: cookie name containing an expiry timestamp
The following code examples show how to generate the signature using PHP.
function getSignedUrlQueryParameter(
string $cdnResourceUrl,
string $filePath,
string $secureToken,
?int $expiryTimestamp = null
): string {
$filePath = '/' . ltrim($filePath, '/'); // Add slash to start of file path if missing
if ($positionOfStartQuery = strpos($filePath, '?')) {
$filePath = substr($filePath, 0, $positionOfStartQuery); // Cut the query string from file path
}
$hash = $filePath . $secureToken;
if ($expiryTimestamp) {
$hash = $expiryTimestamp . $hash;
}
$finalHash = strtr(base64_encode(md5($hash, true)), '+/', '-_'); // Replace invalid URL query string characters
return "https://{$cdnResourceUrl}{$filePath}?secure={$finalHash}" . ($expiryTimestamp ? ",{$expiryTimestamp}" : '');
}
function getSignedUrlPath(
string $cdnResourceUrl,
string $filePath,
string $secureToken,
?int $expiryTimestamp = null
): string {
$strippedPath = substr($filePath, 0, strrpos($filePath, '/'));
$strippedPath = '/' . ltrim($strippedPath, '/');
$filePath = '/' . ltrim($filePath, '/');
if ($positionOfStartQuery = strpos($strippedPath, '?')) {
$filePath = substr($strippedPath, 0, $positionOfStartQuery);
}
$hash = $strippedPath . $secureToken;
if ($expiryTimestamp) {
$hash = $expiryTimestamp . $hash;
}
$finalHash = strtr(base64_encode(md5($hash, true)), '+/', '-_');
return "https://{$cdnResourceUrl}/{$finalHash}" . ($expiryTimestamp ? ",{$expiryTimestamp}" : '') . $filePath;
}