Gateway Signature Specification

2024-01-25
No Rating

When developers send requests from local devices to servers, it is required to use AK/SK authentication in DJI TerraAPI and to add a signature in the developers' request messages using the HMAC signing algorithmopen in new window.

This is an example of a request message sent to a server. This document explains each part of the request and shows a complete example of the request code at the end.

curl -i -X GET http://localhost:8000/requests \
    -H "Host: hmac.com" \
    -H "Date: Thu, 22 Jun 2017 21:12:36 GMT" \
    -H "Digest: SHA-256=SBH7QEtqnYUpEcIhDbmStNd1MxtHg2+feBfWc1105MA=" \
    -H 'Authorization: hmac username="alice123", algorithm="hmac-sha256", headers="date @request-target digest", signature="gaweQbATuaGmLrUr3HE0DzU1keWGCt3H96M28sSHTG8="' \
    -d "A small body"

Signature and Request Process

AK/SK Definition

AK/SK authentication is a method of digitally signing requests using AK/SK. When sending requests, this signature is added to the message header to complete identity verification.

AK (App Key, Access Key ID): This is a unique identifier associated with a private access key. It is used in conjunction with the private access key to encrypt signature request information.

SK (Secret Key, Private Access Key): This is a key used for encrypting signatures. Used together with the Access Key ID, it authenticates the identity of the requester and ensures that the request content has not been tampered with during transmission.

Get AK/SK

Log in to the Developer Websiteopen in new window and enter the DJI TerraAPI Consoleopen in new window. Click the [Apply for Access] button and wait for the backend review. After approval, the DJI TerraAPI Console will display your AK/SK information. The image below shows an example of AK/SK information.

Generating Authorization

keyIDThe username of the credential
algorithmDigital signature algorithm used to create the signature
headersList of HTTP header names, separated by a single space character, used to sign the request
signatureBase64 encoded digital signature generated by the client
credentials := "hmac" params
params := keyId "," algorithm ", " headers ", " signature
keyId := "username" "=" plain-string
algorithm := "algorithm" "=" DQUOTE (hmac-sha1|hmac-sha256|hmac-sha384|hmac-sha512) DQUOTE
headers := "headers" "=" plain-string
signature := "signature" "=" plain-string
plain-string   = DQUOTE *( %x20-21 / %x23-5B / %x5D-7E ) DQUOTE

Generating Digest for Body Signature

Digest: SHA-256=base64(sha256(<body>))

Request Example Code

import requests
import hashlib
import hmac
import base64
from datetime import datetime,timezone
from urllib.parse import urlparse
 
def main():
    # 1. Construct authentication information
    key_id = "alice123"
    algorithm = "hmac-sha256"
    headers = "date @request-target digest"
    secret = b"secret"  # Replace with your actual secret key
 
    # 2. Construct HTTP request
    url = "http://localhost:8000/mock"
    method = "GET"
    body = "A small body"
 
    # 3. Construct necessary header information
    date = get_formatted_date()
    request_target = get_request_target(method, url)
    digest = calculate_digest(body)
 
    # 4. Construct signature string
    signing_string = f"date: {date}\n@request-target: {request_target}\ndigest: SHA-256={digest}"
    signature = generate_signature(secret, signing_string)
 
    # 5. Send HTTP request
    send_http_request(url, method, body, date, request_target, digest, key_id, algorithm, headers, signature)
 
def get_formatted_date():
    return datetime.now(timezone.utc).strftime("%a, %d %b %Y %H:%M:%S GMT")
 
def get_request_target(method, url):
    parsed_url = urlparse(url)
    return f"{method.lower()} {parsed_url.path}"
 
def calculate_digest(body):
    hash_obj = hashlib.sha256(body.encode("utf-8"))
    return base64.b64encode(hash_obj.digest()).decode("utf-8")
 
def generate_signature(secret, signing_string):
    hmac_obj = hmac.new(secret, signing_string.encode("utf-8"), hashlib.sha256)
    return base64.b64encode(hmac_obj.digest()).decode("utf-8")
 
def send_http_request(url, method, body, date, request_target, digest, key_id, algorithm, headers, signature):
    # Make a HTTP request, use your preferred HTTP request library, such as requests
    # Reference: https://docs.python-requests.org/en/latest/
    headers = {
        "Date": date,
        "Authorization": f'hmac username="{key_id}", algorithm="{algorithm}", headers="{headers}", signature="{signature}"',
        "@request-target": request_target,
        "Digest": f"SHA-256={digest}"
    }
 
    response = requests.request(method, url, headers=headers, data=body)
    print("Response Status:", response.status_code)
    print("Response Body:", response.text)
 
if __name__ == "__main__":
    main()