Task Management
signature = base64(HMAC-SHA256(secret_key, signingString))

Where:

  • secret_key: the token used when creating the task
  • signingString: the string to be signed, constructed as follows
signingString = http_method + "\n" + http_uri + "\n" + canonical_query_string + "\n" + access_key + "\n" + Date + "\n" + signed_headers_string

Parameter descriptions:

  • http_method: HTTP request method such as GET, PUT, POST, etc., must be in all uppercase

  • http_uri: the path part of the URL, extracted using a standard URL parser from the callback_url, must start with "/", and an empty path should be "/"

  • canonical_query_string: the query string part of the URL, extracted using a standard URL parser from the callback_url, if there are no query parameters, use an empty string

  • access_key: API identifier, fixed as "vidu"

  • Date: the Date in the request header (in GMT format)

  • signed_headers_string: extract headers specified in X-HMAC-SIGNED-HEADERS from the request in order, and concatenate them in the following format:

    HeaderKey1 + ":" + HeaderValue1 + "\n" +
    HeaderKey2 + ":" + HeaderValue2 + "\n" +
    ...
    HeaderKeyN + ":" + HeaderValueN + "\n"

Headers related to the signature include:

  • Date: time in GMT format, e.g., "Tue, 06 May 2025 12:09:42 GMT"
  • x-request-nonce: random string to prevent replay attacks
  • X-HMAC-SIGNED-HEADERS: list of header fields used in the signature, separated by semicolons, e.g., "Date;x-request-nonce"
  • X-HMAC-SIGNATURE: the final computed signature
  • X-HMAC-ALGORITHM: signature algorithm, fixed as "hmac-sha256"
  • X-HMAC-ACCESS-KEY: access key identifier, fixed as "vidu"

Using a standard URL parser to parse the full URL

http://127.0.0.1:8080/vidu/callback?name=james&age=36
, the final signing string generated is:

POST
/vidu/callback
name=james&age=36
vidu
Tue, 06 May 2025 12:09:42 GMT
Date:Tue, 06 May 2025 12:09:42 GMT
x-request-nonce:123e4567-e89b-12d3-a456-426614174000

Notes:

  1. The string ends with a newline character
  2. /vidu/callback is the Path part extracted from the URL using a standard URL parser
  3. name=james&age=36 is the RawQuery part extracted from the URL using a standard URL parser
  4. The secret used for the signature is the application's TokenSecret
import base64
import hmac
import hashlib
import urllib.parse
import uuid

def generate_signature(secret_key, http_method, callback_url, date, headers, header_order):
    # Parse the URL using a standard URL parsing library
    parsed_url = urllib.parse.urlparse(callback_url)
    uri = parsed_url.path or "/"
    query_string = parsed_url.query or ""
    
    # Construct the signing string
    signing_string = (
        f"{http_method}\n"
        f"{uri}\n"
        f"{query_string}\n"
        f"vidu\n"  # Fixed access_key
        f"{date}\n"
    )
    
    # Add header information
    for header in header_order:
        signing_string += f"{header}:{headers[header]}\n"
    
    # Compute the signature
    h = hmac.new(
        secret_key.encode('utf-8'),
        signing_string.encode('utf-8'),
        hashlib.sha256
    )
    
    # Base64 encode
    return base64.b64encode(h.digest()).decode('utf-8')

# Example usage
secret_key = 'your_secret_token'
http_method = 'POST'
callback_url = 'http://127.0.0.1:8080/vidu/callback?name=james&age=36'
date = 'Tue, 06 May 2025 12:09:42 GMT'
nonce = str(uuid.uuid4())
headers = {
    'Date': date,
    'x-request-nonce': nonce
}
header_order = ['Date', 'x-request-nonce']

signature = generate_signature(secret_key, http_method, callback_url, date, headers, header_order)
print(signature)

# Build the complete HTTP request headers
request_headers = {
    'Date': date,
    'x-request-nonce': nonce,
    'X-HMAC-SIGNED-HEADERS': ';'.join(header_order),
    'X-HMAC-SIGNATURE': signature,
    'X-HMAC-ALGORITHM': 'hmac-sha256',
    'X-HMAC-ACCESS-KEY': 'vidu',
    'Content-Type': 'application/json'
}
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"net/url"
	"strings"
	"time"
	
	"github.com/google/uuid"
)

func generateSignature(secretKey, httpMethod, callbackURL, date string, headers map[string]string, headerOrder []string) (string, error) {
	// Parse the URL using a standard URL parsing library
	uri := "/"
	queryString := ""
	
	parsedURL, err := url.Parse(callbackURL)
	if err != nil {
		return "", err
	}
	
	// Get the Path part
	if parsedURL.Path != "" {
		uri = parsedURL.Path
	}
	
	// Get the query parameters part
	queryString = parsedURL.RawQuery

	var signingStringBuilder strings.Builder
	
	// Add HTTP method
	signingStringBuilder.WriteString(httpMethod)
	signingStringBuilder.WriteString("\n")

	// Add URI
	signingStringBuilder.WriteString(uri)
	signingStringBuilder.WriteString("\n")

	// Add query string
	signingStringBuilder.WriteString(queryString)
	signingStringBuilder.WriteString("\n")

	// Add access key
	signingStringBuilder.WriteString("vidu")
	signingStringBuilder.WriteString("\n")

	// Add date
	signingStringBuilder.WriteString(date)
	signingStringBuilder.WriteString("\n")

	// Add headers
	for _, header := range headerOrder {
		signingStringBuilder.WriteString(header)
		signingStringBuilder.WriteString(":")
		signingStringBuilder.WriteString(headers[header])
		signingStringBuilder.WriteString("\n")
	}

	signingString := signingStringBuilder.String()

	// Generate HMAC-SHA256
	h := hmac.New(sha256.New, []byte(secretKey))
	h.Write([]byte(signingString))

	// Base64 encode
	return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
}

func main() {
	secretKey := "your_secret_token"
	httpMethod := "POST"
	callbackURL := "http://127.0.0.1:8080/vidu/callback?name=james&age=36"
	currentTime := time.Now().UTC()
	date := currentTime.Format("Mon, 02 Jan 2006 15:04:05 GMT")
	nonce := uuid.New().String()
	
	headers := map[string]string{
		"Date":            date,
		"x-request-nonce": nonce,
	}
	
	headerOrder := []string{"Date", "x-request-nonce"}
	
	signature, err := generateSignature(secretKey, httpMethod, callbackURL, date, headers, headerOrder)
	if err != nil {
		fmt.Printf("Error generating signature: %v\n", err)
		return
	}
	
	fmt.Println("Signature:", signature)
	
	// Build the complete HTTP request headers
	requestHeaders := map[string]string{
		"Date":                 date,
		"x-request-nonce":      nonce,
		"X-HMAC-SIGNED-HEADERS": strings.Join(headerOrder, ";"),
		"X-HMAC-SIGNATURE":     signature,
		"X-HMAC-ALGORITHM":     "hmac-sha256",
		"X-HMAC-ACCESS-KEY":    "vidu",
		"Content-Type":         "application/json",
	}
	
	for k, v := range requestHeaders {
		fmt.Printf("%s: %s\n", k, v)
	}
}
  1. The signing string is very sensitive to formatting, including newline characters and spaces
  2. When using multi-line strings, make sure:
    • There are no extra indentation spaces
    • The format between lines is precise
    • The string ends with a newline character
  3. The headers specified in X-HMAC-SIGNED-HEADERS must be concatenated in the specified order
  4. The HTTP method must be uppercase (e.g., POST, GET, etc.)
  5. The URI must start with "/"
  6. Query parameters must be in raw format, without including the "?"
  7. During signature generation, the system uses a standard URL parser to extract the URI and query parameter parts from callback_url
  8. To prevent replay attacks, use the x-request-nonce header with a random value (UUID format)