Generate signatures

This guide explains how to create a signature, and the required and optional fields for signatures.

To create a signature, you compose a string to sign, which we refer to as a signed value in this guide. The signed value includes parameters that describe the content you are protecting, the expiration time of the signed value, and so forth.

You use the signed value while creating a signature string. You create a signature string by composing the parameters for the signature, such as an asymmetric-key Ed25519 signature of the signed value.

Media CDN uses the final composed signature to help protect your content.

Supported signing formats

Media CDN supports the following signed request formats.

Format Behavior Example
Query parameters (exact URL)

Exact URL, for granting access to a specific URL.

Exact:

https://media.example.com/content/manifest.m3u8?
Expires= EXPIRATION
&KeyName= KEY_NAME
&Signature= SIGNATURE

Query parameters (URL prefix)
Specifying a URLPrefix lets you sign a prefix and append the same query parameters to multiple URLs within your player or manifest generation.

What to sign:

URLPrefix= PREFIX
&Expires= EXPIRATION
&KeyName= KEY_NAME
&Signature= SIGNATURE

Replace PREFIX with the prefix to grant access to, including the scheme, host, and partial path.

Path component

Prefix: allows access to any URL with a prefix prior to the "/edge-cache-token=[...]" component.

This allows relative manifest URLs to automatically inherit the signed URL component when fetching sub-resources.

https://media.example.com/video/edge-cache-token=Expires= EXPIRATION
&KeyName= KEY_NAME
&Signature= SIGNATURE /manifest_12382131.m3u8
Signed cookie
Prefix: the cookie allows access to any URL with the prefix specified in the signed URLPrefix value.

Edge-Cache-Cookie:

URLPrefix= PREFIX :
Expires= EXPIRATION :
KeyName= KEY_NAME :
Signature= SIGNATURE

Create a signature

  1. Create a signed value by concatenating a string that contains the required signature fields and desired optional signature fields .

    If specified, URLPrefix must come first, followed by Expires , KeyName , and then any optional parameters.

    Separate each field and any parameters with the following:

    • For cookies, use a colon : character.
    • For query parameters and path components, use an ampersand & character.
  2. Sign the signed value with an Ed25519 signature.

  3. Append a field separator (either : or & ) followed by Signature= and the Ed25519 signature to the end of the string.

Create a signed URL

The following code samples shows how to programmatically create a signed URL.

Go

To authenticate to Media CDN, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  import 
  
 ( 
  
 "crypto/ed25519" 
  
 "encoding/base64" 
  
 "fmt" 
  
 "io" 
  
 "strings" 
  
 "time" 
 ) 
 // signURL prints the signed URL string for the specified URL and configuration. 
 func 
  
 signURL 
 ( 
 w 
  
 io 
 . 
 Writer 
 , 
  
 url 
 , 
  
 keyName 
  
 string 
 , 
  
 privateKey 
  
 [] 
 byte 
 , 
  
 expires 
  
 time 
 . 
 Time 
 ) 
  
 error 
  
 { 
  
 // url := "http://example.com" 
  
 // keyName := "your_key_name" 
  
 // privateKey := "[]byte{34, 31, ...}" 
  
 // expires := time.Unix(1558131350, 0) 
  
 sep 
  
 := 
  
 '?' 
  
 if 
  
 strings 
 . 
 ContainsRune 
 ( 
 url 
 , 
  
 '?' 
 ) 
  
 { 
  
 sep 
  
 = 
  
 '&' 
  
 } 
  
 toSign 
  
 := 
  
 fmt 
 . 
 Sprintf 
 ( 
 "%s%cExpires=%d&KeyName=%s" 
 , 
  
 url 
 , 
  
 sep 
 , 
  
 expires 
 . 
 Unix 
 (), 
  
 keyName 
 ) 
  
 sig 
  
 := 
  
 ed25519 
 . 
 Sign 
 ( 
 privateKey 
 , 
  
 [] 
 byte 
 ( 
 toSign 
 )) 
  
 fmt 
 . 
 Fprintf 
 ( 
 w 
 , 
  
 "%s&Signature=%s" 
 , 
  
 toSign 
 , 
  
 base64 
 . 
 RawURLEncoding 
 . 
 EncodeToString 
 ( 
 sig 
 )) 
  
 return 
  
 nil 
 } 
 

Python

To authenticate to Media CDN, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  import 
  
 base64 
 import 
  
 datetime 
 import 
  
 cryptography.hazmat.primitives.asymmetric.ed25519 
  
 as 
  
 ed25519 
 from 
  
 six.moves 
  
 import 
 urllib 
 def 
  
 sign_url 
 ( 
 url 
 : 
 str 
 , 
 key_name 
 : 
 str 
 , 
 base64_key 
 : 
 str 
 , 
 expiration_time 
 : 
 datetime 
 . 
 datetime 
 ) 
 - 
> str 
 : 
  
 """Gets the Signed URL string for the specified URL and configuration. 
 Args: 
 url: URL to sign as a string. 
 key_name: name of the signing key as a string. 
 base64_key: signing key as a base64 encoded byte string. 
 expiration_time: expiration time as a UTC datetime object. 
 Returns: 
 Returns the Signed URL appended with the query parameters based on the 
 specified configuration. 
 """ 
 stripped_url 
 = 
 url 
 . 
 strip 
 () 
 parsed_url 
 = 
 urllib 
 . 
 parse 
 . 
 urlsplit 
 ( 
 stripped_url 
 ) 
 query_params 
 = 
 urllib 
 . 
 parse 
 . 
 parse_qs 
 ( 
 parsed_url 
 . 
 query 
 , 
 keep_blank_values 
 = 
 True 
 ) 
 epoch 
 = 
 datetime 
 . 
 datetime 
 . 
 utcfromtimestamp 
 ( 
 0 
 ) 
 expiration_timestamp 
 = 
 int 
 (( 
 expiration_time 
 - 
 epoch 
 ) 
 . 
 total_seconds 
 ()) 
 decoded_key 
 = 
 base64 
 . 
 urlsafe_b64decode 
 ( 
 base64_key 
 ) 
 url_pattern 
 = 
 " 
 {url}{separator} 
 Expires= 
 {expires} 
& KeyName= 
 {key_name} 
 " 
 url_to_sign 
 = 
 url_pattern 
 . 
 format 
 ( 
 url 
 = 
 stripped_url 
 , 
 separator 
 = 
 "&" 
 if 
 query_params 
 else 
 "?" 
 , 
 expires 
 = 
 expiration_timestamp 
 , 
 key_name 
 = 
 key_name 
 , 
 ) 
 digest 
 = 
 ed25519 
 . 
 Ed25519PrivateKey 
 . 
 from_private_bytes 
 ( 
 decoded_key 
 ) 
 . 
 sign 
 ( 
 url_to_sign 
 . 
 encode 
 ( 
 "utf-8" 
 ) 
 ) 
 signature 
 = 
 base64 
 . 
 urlsafe_b64encode 
 ( 
 digest 
 ) 
 . 
 decode 
 ( 
 "utf-8" 
 ) 
 signed_url 
 = 
 " 
 {url} 
& Signature= 
 {signature} 
 " 
 . 
 format 
 ( 
 url 
 = 
 url_to_sign 
 , 
 signature 
 = 
 signature 
 ) 
 return 
 signed_url 
 

Create a signed URL prefix

The following code samples show how to programmatically create a signed URL prefix.

Go

To authenticate to Media CDN, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  import 
  
 ( 
  
 "crypto/ed25519" 
  
 "encoding/base64" 
  
 "fmt" 
  
 "io" 
  
 "strings" 
  
 "time" 
 ) 
 // signURLPrefix prints the signed URL string for the specified URL prefix and configuration. 
 func 
  
 signURLPrefix 
 ( 
 w 
  
 io 
 . 
 Writer 
 , 
  
 urlPrefix 
 , 
  
 keyName 
  
 string 
 , 
  
 privateKey 
  
 [] 
 byte 
 , 
  
 expires 
  
 time 
 . 
 Time 
 ) 
  
 error 
  
 { 
  
 // urlPrefix := "https://examples.com" 
  
 // keyName := "your_key_name" 
  
 // privateKey := "[]byte{34, 31, ...}" 
  
 // expires := time.Unix(1558131350, 0) 
  
 sep 
  
 := 
  
 '?' 
  
 if 
  
 strings 
 . 
 ContainsRune 
 ( 
 urlPrefix 
 , 
  
 '?' 
 ) 
  
 { 
  
 sep 
  
 = 
  
 '&' 
  
 } 
  
 toSign 
  
 := 
  
 fmt 
 . 
 Sprintf 
 ( 
  
 "URLPrefix=%s&Expires=%d&KeyName=%s" 
 , 
  
 base64 
 . 
 RawURLEncoding 
 . 
 EncodeToString 
 ([] 
 byte 
 ( 
 urlPrefix 
 )), 
  
 expires 
 . 
 Unix 
 (), 
  
 keyName 
 , 
  
 ) 
  
 sig 
  
 := 
  
 ed25519 
 . 
 Sign 
 ( 
 privateKey 
 , 
  
 [] 
 byte 
 ( 
 toSign 
 )) 
  
 fmt 
 . 
 Fprintf 
 ( 
  
 w 
 , 
  
 "%s%c%s&Signature=%s" 
 , 
  
 urlPrefix 
 , 
  
 sep 
 , 
  
 toSign 
 , 
  
 base64 
 . 
 RawURLEncoding 
 . 
 EncodeToString 
 ( 
 sig 
 ), 
  
 ) 
  
 return 
  
 nil 
 } 
 

Python

To authenticate to Media CDN, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  import 
  
 base64 
 import 
  
 datetime 
 import 
  
 cryptography.hazmat.primitives.asymmetric.ed25519 
  
 as 
  
 ed25519 
 from 
  
 six.moves 
  
 import 
 urllib 
 def 
  
 sign_url_prefix 
 ( 
 url 
 : 
 str 
 , 
 url_prefix 
 : 
 str 
 , 
 key_name 
 : 
 str 
 , 
 base64_key 
 : 
 str 
 , 
 expiration_time 
 : 
 datetime 
 . 
 datetime 
 , 
 ) 
 - 
> str 
 : 
  
 """Gets the Signed URL string for the specified URL prefix and configuration. 
 Args: 
 url: URL of request. 
 url_prefix: URL prefix to sign as a string. 
 key_name: name of the signing key as a string. 
 base64_key: signing key as a base64 encoded string. 
 expiration_time: expiration time as a UTC datetime object. 
 Returns: 
 Returns the Signed URL appended with the query parameters based on the 
 specified URL prefix and configuration. 
 """ 
 stripped_url 
 = 
 url 
 . 
 strip 
 () 
 parsed_url 
 = 
 urllib 
 . 
 parse 
 . 
 urlsplit 
 ( 
 stripped_url 
 ) 
 query_params 
 = 
 urllib 
 . 
 parse 
 . 
 parse_qs 
 ( 
 parsed_url 
 . 
 query 
 , 
 keep_blank_values 
 = 
 True 
 ) 
 encoded_url_prefix 
 = 
 base64 
 . 
 urlsafe_b64encode 
 ( 
 url_prefix 
 . 
 strip 
 () 
 . 
 encode 
 ( 
 "utf-8" 
 ) 
 ) 
 . 
 decode 
 ( 
 "utf-8" 
 ) 
 epoch 
 = 
 datetime 
 . 
 datetime 
 . 
 utcfromtimestamp 
 ( 
 0 
 ) 
 expiration_timestamp 
 = 
 int 
 (( 
 expiration_time 
 - 
 epoch 
 ) 
 . 
 total_seconds 
 ()) 
 decoded_key 
 = 
 base64 
 . 
 urlsafe_b64decode 
 ( 
 base64_key 
 ) 
 policy_pattern 
 = 
 ( 
 "URLPrefix= 
 {encoded_url_prefix} 
& Expires= 
 {expires} 
& KeyName= 
 {key_name} 
 " 
 ) 
 policy 
 = 
 policy_pattern 
 . 
 format 
 ( 
 encoded_url_prefix 
 = 
 encoded_url_prefix 
 , 
 expires 
 = 
 expiration_timestamp 
 , 
 key_name 
 = 
 key_name 
 , 
 ) 
 digest 
 = 
 ed25519 
 . 
 Ed25519PrivateKey 
 . 
 from_private_bytes 
 ( 
 decoded_key 
 ) 
 . 
 sign 
 ( 
 policy 
 . 
 encode 
 ( 
 "utf-8" 
 ) 
 ) 
 signature 
 = 
 base64 
 . 
 urlsafe_b64encode 
 ( 
 digest 
 ) 
 . 
 decode 
 ( 
 "utf-8" 
 ) 
 signed_url 
 = 
 " 
 {url}{separator}{policy} 
& Signature= 
 {signature} 
 " 
 . 
 format 
 ( 
 url 
 = 
 stripped_url 
 , 
 separator 
 = 
 "&" 
 if 
 query_params 
 else 
 "?" 
 , 
 policy 
 = 
 policy 
 , 
 signature 
 = 
 signature 
 , 
 ) 
 return 
 signed_url 
 

The following code samples show how to programmatically create a signed URL cookie.

Create a signed path component

The following code samples show how to programmatically create a signed path component.

Python

To authenticate to Media CDN, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  import 
  
 base64 
 import 
  
 datetime 
 import 
  
 hashlib 
 import 
  
 hmac 
 import 
  
 cryptography.hazmat.primitives.asymmetric.ed25519 
  
 as 
  
 ed25519 
 def 
  
 base64_encoder 
 ( 
 value 
 : 
 bytes 
 ) 
 - 
> str 
 : 
  
 """ 
 Returns a base64-encoded string compatible with Media CDN. 
 Media CDN uses URL-safe base64 encoding and strips off the padding at the 
 end. 
 """ 
 encoded_bytes 
 = 
 base64 
 . 
 urlsafe_b64encode 
 ( 
 value 
 ) 
 encoded_str 
 = 
 encoded_bytes 
 . 
 decode 
 ( 
 "utf-8" 
 ) 
 return 
 encoded_str 
 . 
 rstrip 
 ( 
 "=" 
 ) 
 def 
  
 sign_path_component 
 ( 
 url_prefix 
 : 
 str 
 , 
 filename 
 : 
 str 
 , 
 key_name 
 : 
 str 
 , 
 base64_key 
 : 
 str 
 , 
 expiration_time 
 : 
 datetime 
 . 
 datetime 
 , 
 ) 
 - 
> str 
 : 
  
 """Gets the Signed URL string for the specified URL prefix and configuration. 
 Args: 
 url_prefix: URL Prefix to sign as a string. 
 filename: The filename of the sample request 
 key_name: The name of the signing key as a string. 
 base64_key: The signing key as a base64 encoded string. 
 expiration_time: Expiration time as a UTC datetime object with timezone. 
 Returns: 
 Returns the Signed URL appended with the query parameters based on the 
 specified URL prefix and configuration. 
 """ 
 expiration_duration 
 = 
 expiration_time 
 . 
 astimezone 
 ( 
 tz 
 = 
 datetime 
 . 
 timezone 
 . 
 utc 
 ) 
 - 
 datetime 
 . 
 datetime 
 . 
 fromtimestamp 
 ( 
 0 
 , 
 tz 
 = 
 datetime 
 . 
 timezone 
 . 
 utc 
 ) 
 decoded_key 
 = 
 base64 
 . 
 urlsafe_b64decode 
 ( 
 base64_key 
 ) 
 policy_pattern 
 = 
 " 
 {url_prefix} 
 edge-cache-token=Expires= 
 {expires} 
& KeyName= 
 {key_name} 
 " 
 policy 
 = 
 policy_pattern 
 . 
 format 
 ( 
 url_prefix 
 = 
 url_prefix 
 , 
 expires 
 = 
 int 
 ( 
 expiration_duration 
 . 
 total_seconds 
 ()), 
 key_name 
 = 
 key_name 
 , 
 ) 
 digest 
 = 
 ed25519 
 . 
 Ed25519PrivateKey 
 . 
 from_private_bytes 
 ( 
 decoded_key 
 ) 
 . 
 sign 
 ( 
 policy 
 . 
 encode 
 ( 
 "utf-8" 
 ) 
 ) 
 signature 
 = 
 base64_encoder 
 ( 
 digest 
 ) 
 signed_url 
 = 
 " 
 {policy} 
& Signature= 
 {signature} 
 / 
 {filename} 
 " 
 . 
 format 
 ( 
 policy 
 = 
 policy 
 , 
 signature 
 = 
 signature 
 , 
 filename 
 = 
 filename 
 ) 
 return 
 signed_url 
 

Required signature fields

The following fields are required for every signature:

  • Expires
  • KeyName
  • Signature

If query parameters are present, they must be grouped together as the last parameters in the URL. Unless otherwise specified, parameter names and their values are case-sensitive.

The following table explains each parameter:

Field name Signature parameters Signed value
Expires
Integer seconds that have elapsed since the Unix epoch (1970-01-01T00:00:00Z) Expires= EXPIRATION_TIME , after which the signature is no longer valid.
KeyName
The name of the EdgeCacheKeyset used to sign this request. KeyName refers to the entire keyset, not individual keys within the keyset itself. KeyName= EDGE_CACHE_KEYSET
Signature
A base-64 encoded version of the signature. Not applicable

Optional signature fields

If query parameters are present, they must be grouped together as the last parameters in the URL. Unless otherwise specified, parameter names and their values are case-sensitive.

The following table explains each parameter's name and detail for optional signature parameters:

Field name
Signature parameters
Signed value
HeaderName

A named request header field name that must be present in the request.

Must be lowercase when signed because header field names are case-sensitive. Media CDN lowercases the header before validating the signature.

HeaderName= HEADER_NAME
HeaderValue
A named request header field value that must be present in the request. This is commonly a user ID or other opaque identifier. Requests with HeaderValue but without HeaderName are rejected.
HeaderValue= HEADER_VALUE
IPRanges

A list of up to five IPv4 and IPv6 addresses in CIDR format for which this URL is valid in web-safe base64 format. For example, to specify the IP ranges "192.6.13.13/32,193.5.64.135/32", you specify IPRanges=MTkyLjYuMTMuMTMvMzIsMTkzLjUuNjQuMTM1LzMy .

IPRanges may not be helpful to include in signatures when clients are at risk of WAN migrations or cases where the network path to your application frontend is different than the delivery path. Media CDN rejects clients with an HTTP 403 code when they connect with an IP address that is not part of the signed request.

The following are cases that may result in Media CDN rejecting clients with an HTTP 403 code:

  • Dual-stack (IPv4, IPv6) environments
  • Connection migration (WiFi to cellular, and cellular to WiFi)
  • Mobile networks that use Carrier Gateway NAT (CGNAT or CGN)
  • Multi-path TCP (MPTCP)

All of these factors can contribute to a given client having a non-deterministic IP address during a video playback session. If the client IP address changes after you have issued access, and the client attempts to then download a video segment into their playback buffer, they receive an HTTP 403 from Media CDN.

IPRanges= BASE_64_IP_RANGES
URLPrefix
The base64 (URL-safe) URL prefix to grant access to. Specifying a URLPrefix lets you sign a prefix and append the same query parameters to multiple URLs within your player or manifest generation. The URLPrefix is required when using the signed cookie format.
URLPrefix= BASE_64_URL_PREFIX
Design a Mobile Site
View Site in Mobile | Classic
Share by: