API Security

Message Signing and Verification

Messages between Provider and Aggregator and Aggregator and Operator, need to be signed on the sender and verified on the receiver。

The API_KEY and API_KEY_SECRET will be generated when Operator or Provider is added into Aggregator.

API_KEY and API_KEY_SECRET

For API_KEY, we can remove the hyphens from a UUID as the value.

For API_KEY_SECRET, we can generate a random Base64 string as the value with the Golang code below.

func generateAPIKeySecret(length int) (string, error) {
        if length <= 0 {
                return "", fmt.Errorf("length must be positive")
        }

    // Calculate the number of random bytes needed.
    // Base64 encoding expands the data by 4/3, so we need to generate less bytes
    // to get the desired length after encoding. We round up to ensure we get at least the desired length.
    b := make([]byte, (length*3+3)/4)
        _, err := rand.Read(b)
        if err != nil {
                return "", fmt.Errorf("error generating random bytes: %w", err)
        }
        return base64.StdEncoding.EncodeToString(b), nil
}

Signing and Verification

Before signing the message, we need to generate the canonicalized message from the request.

For GET request, the canonicalized message will be the key=value pairs concatenated with & as below.

key_a=value_a&key_b=value_b&key_c=value_c

For other request like POST, the canonicalized message will be the request body.

HMAC-SHA256 will be used for signing the message to get the signature.

SIGNATURE=HMAC-SHA256(API_SECRET, canonicalized_request_string)

After message is signed on the sender side, we will include API_KEY and signature generated above in two extra headers as below in the http request.

X-API-KEY: {API_KEY}
X-SIGNATURE: {SIGNATURE} 

On the receiver side, API_KEY in X-API-KEY header will be used to retrieve the API_KEY_SECRET from the database and sign the message to get the signature and compare with X-SIGNATURE header value. If they are identical, the message can be further processed by Aggregator, otherwise dropped and return http status code 403 with Unauthenticated error to the sender.

Last updated