How to set up CDN URL Token Authentication

URL Token Authentication allows you to generate secure URLs that expire after the set timestamp and are only accessible using a token generated using a secret key and an expiry timestamp. This guide will explain how to set up the CDN URL Token Authentication on BunnyCDN.

Step 1: Enable URL Token Authentication on your Pull Zone

To generate the secure token, you will first need to enable URL Token Authentication in the Dashboard and then copy your Token security key from the URL Token Authentication box.

Step 2: Generate the URL

To create a secure URL, you must add a token and expires query parameters to the URL that you want to access. The expires parameter is the UNIX timestamp marking until when the URL is accessible. After this passes, the URL will no longer be accessible.

The token parameter is a Base64 encoded MD5 hash based on the key, URL and any extra parameters. To generate the token, you can use the following algorithm. 

MD5(token_security_key + url_path + expiration). To properly format the token you have to then replace the following characters in the resulting Base64 string: '\n' with '', '+' with '-', '/' with '_' and '=' with ''

An example secure URL will then look like:

https://test.b-cdn.net/assets/favicon.ico?token=m0EMEkV3pNAKFB33gZuv_Q&expires=1456761770 

Code examples:

To make things easier, we also provide code examples for most popular languages below.

PHP Example

$securityKey = 'token_security_key';
$path = '/pathto/file.jpg';

// Set the time of expiry to one hour from now
$expires = time() + 3600; 

// Generate the token
$hashableBase = $securityKey.$path.$expires;

// If using IP validation
// $hashableBase .= "146.14.19.7";
$token = md5($hashableBase, true); $token = base64_encode($token); $token = strtr($token, '+/', '-_'); $token = str_replace('=', '', $token); // Generate the URL $url = "https://myzone.b-cdn.net{$path}?token={$token}&expires={$expires}";

C# .NET Example

var securityKey = "token_security_key";
var path = "/pathto/file.jpg";

// Load the current time
var unixBaseTime = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);
var currentTime = ((long)(DateTime.UtcNow - unixBaseTime).TotalSeconds);

// Set the time of expiry to one hour from now
var expires = currentTime + 3600; 

// Generate the token
System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();

string hashableBase = securityKey + path + expires;

// If using IP validation
// hashableBase += "146.14.19.7";

byte[] outpufBuffer = md5.ComputeHash(Encoding.UTF8.GetBytes(hashableBase));
var token = Convert.ToBase64String(outpufBuffer);
token = token.Replace("\n", "").Replace("+", "-").Replace("/", "_").Replace("=", "");

// Generate the URL
var url = $"https://myzone.b-cdn.net{path}?token={token}&expires={expires}";

Node.JS JavaScript Example

var crypto = require('crypto'),
securityKey = 'token_security_key',
path = '/pathto/file.jpg';

// Set the time of expiry to one hour from now
var expires = Math.round(Date.now() / 1000) + 3600;

var hashableBase = securityKey + path + expires;

// If using IP validation
// hashableBase += "146.14.19.7";

// Generate and encode the token
var md5String = crypto.createHash("md5").update(hashableBase).digest("binary");
var token = new Buffer(md5String, 'binary').toString('base64');
token = token.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');

// Generate the URL
var url = 'https://myzone.b-cdn.net' + path + '?token=' + token + '&expires=' + expires;

Python Example

#!/usr/bin/env python3
import hashlib
from base64 import b64encode
from time import time

def generate_secure_url(security_key, path,
                        expire_timeframe=3600,
                        base_url=str(),
filtered_ip=""): """Generate BunnyCDN URL authentication token. Arguments: security_key (str): Generated token from the panel. path (str): /path/to/file.ext, with the initial slash included. expire_timeframe (int): Time until expiry, in seconds. base_url (str): CDN's base URL of the site, without ending slash. filtered_ip: The IP that should be included in the hash. Use this if doing IP validation.
Returns: str: URL """ expire_timestamp = int(time()) + 3600 token_content = '{key}{path}{timestamp}{filtered_ip}'.format(key=security_key,path=path,timestamp=expire_timestamp) md5sum = hashlib.md5() md5sum.update(token_content.encode('ascii')) token_digest = md5sum.digest() token_base64 = b64encode(token_digest).decode('ascii') token_formatted = token_base64.replace('\n', '').replace('+', '-').replace('/', '_').replace('=', '')
// Build the URL url = '{base_url}{path}?token={token}&expires={expire_timestamp}'.format( base_url=base_url, path=path, token=token_formatted, expire_timestamp=expire_timestamp) return url # Example usage: // Returns: '/index.html?token=IuNSzXOiYkL-LmGJcwxMQg&expires=1488672404' generate_secure_url('super-secret-code', '/index.html') // Returns: 'https://test.b-cdn.net/index.html?token=EuS4D8fFlTrT6zO4FymvUw&expires=1488672453' generate_secure_url('super-secret-code', '/index.html', 31536000, 'https://test.b-cdn.net')
Was this article helpful?
14 out of 21 found this helpful

Comments

11 comments

  • With .NET 4.6 or .NET Core, you can use DateTimeOffset.Now.AddHours(1).ToUnixTimeSeconds() instead of having to define that unixBaseTime variable.

    1
  • Does this feature allow partial suffix files to use Token, while other suffix files are unrestricted?

    0
  • Is it possible to support the folder depth with token ? How to work with m3u8 file ? M3u8 has so many ts file inside and now it is not allow to access from m3u8.

    0
  • We are currently preparing the documentation for Token Version 2 which allows country code blocking, improved hashing security, and directory-based tokens. We hope to release this soon.

    0
  • When is directory based tokens expected to be released?

    1
  • any update on directory based tokens ?

    1
  • Any updates on directory tokens?

    1
  • I am waiting for directory tokens too. Please give us an ETA.

    1
  • Thank you for the feedback. We have just added the directory tokens today and will be preparing the documentation shortly.

    0
  • Thanks.

    0
  • Just evaluating BunnyCDN for a service where users can create their own photo gallery. My current understanding is that URL Token Authentication is the only mechanism which allows us to prevent unauthorized visitors to access files from Cloud Storage. In my case: which prevents a visitor knowing the path to a photo to access it.

    If there are other ways or if I otherwise misunderstood something, I would be very glad if told!

    Directory tokens would be highly welcome. Otherwise we would need to create a new token for every file (in our case photos in a gallery) on a regular recurring basis - which would pretty much negate any advantages BunnyCDN offers us. I know the feature is in the pipe but takes a bit more time. Could you maybe already describe in two sentences how it will work?

    You also mentioned improved hashing security. This would also be very welcome. Any news on that?

    (While I am no cryptographer I am nevertheless pretty sure we should be at least very careful when considering MD5 for cryptographic purposes. Not sure how well the latest pre-image attacks on MD5 work in our use case here... But I would be very thankful if I could choose something I know to be unproblematic)

    Thanks!

    0

Please sign in to leave a comment.