Signature authentication

更新时间:
复制 MD 格式

All Function Compute API requests must be signed, whether sent over HTTP or HTTPS. Function Compute verifies identity by validating the Authorization header of each request. A request is accepted only if the client uses the same signature algorithm as Function Compute.

If a function has an HTTP trigger configured for anonymous access, signature verification is skipped. For all other requests, a missing or invalid Authorization header causes Function Compute to return HTTP status code 403. Rejected requests are not charged. For details, see Billing overview.

Tip: Function Compute SDKs handle signing automatically. If you use an SDK, you do not need to implement this algorithm manually. See SDKs.

How signing works

The signature is computed using HMAC-SHA256 over a canonical string derived from the request, then Base64-encoded. The resulting Authorization header takes the following form:

Authorization = "FC " + accessKeyID + ":" + signature

The signature is computed as:

signature = Base64(HMAC-SHA256(AccessKey secret, string-to-sign))

Where string-to-sign is constructed by concatenating the following components, each separated by a newline (\n):

HTTP_METHOD + "\n"
+ CONTENT-MD5 + "\n"
+ CONTENT-TYPE + "\n"
+ DATE + "\n"
+ CanonicalizedFCHeaders
+ CanonicalizedResource

String-to-sign components

ComponentDescription
HTTP_METHODThe HTTP method in uppercase: GET, PUT, POST, or DELETE.
CONTENT-MD5The MD5 hash of the request body. Leave blank if the request has no Content-MD5 header.
CONTENT-TYPEThe request body type. Function Compute requires application/json.
DATEThe request timestamp in RFC 1123 GMT format. Cannot be blank. Example: Mon, 02 Jan 2006 15:04:05 GMT.
CanonicalizedFCHeadersA canonicalized string of all x-fc- prefixed request headers. See CanonicalizedFCHeaders.
CanonicalizedResourceThe canonical request URL path. See CanonicalizedResource.
Important

The clock skew between when you generate the signature and when Function Compute receives the request must not exceed 15 minutes. Requests outside this window are rejected.

CanonicalizedFCHeaders

Build the CanonicalizedFCHeaders value in three steps:

  1. Collect all HTTP header fields whose names start with x-fc-. Convert each header name to lowercase.

  2. Format each header as ${key}:${value}\n. Sort the formatted strings alphabetically by header name.

  3. Concatenate the sorted strings.

Example: The header X-Fc-Invocation-Type:Sync becomes x-fc-invocation-type:Sync\n.

The following pseudocode (JavaScript) implements this logic:

// prefix = 'x-fc-'
function buildCanonicalHeaders(headers, prefix) {
    var list = [];
    var keys = Object.keys(headers);

    var fcHeaders = {};
    for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        var lowerKey = key.toLowerCase().trim();
        if (lowerKey.startsWith(prefix)) {
            list.push(lowerKey);
            fcHeaders[lowerKey] = headers[key];
        }
    }
    list.sort();

    var canonical = '';
    for (var _i = 0; _i < list.length; _i++) {
        var _key = list[_i];
        canonical += `${_key}:${fcHeaders[_key]}\n`;
    }

    return canonical;
}

CanonicalizedResource

The CanonicalizedResource is derived from the request URL path. The URL path uses the format $api-version/api-path, where:

  • api-version: the API version, currently 2016-08-15.

  • api-path: the operation-specific path. For example, the CreateService operation uses /services. See List of operations by function.

Function Compute processes CanonicalizedResource differently depending on the request type.

Common requests (all requests except those for HTTP-trigger functions requiring authentication):

URL-decode the path and discard the query string. Use only the content before ?.

Requests for HTTP-trigger functions with authentication required:

URL-decode the full path. If the request has query parameters, sort all key-value pairs alphabetically and separate them with \n, then append to the decoded path. If there are no query parameters, append \n to the end of the decoded path.

When a parameter key maps to multiple values, treat the key and all its values as a single unit when sorting.

Example — HTTP trigger with authentication:

// Original URL (URL-encoded):
/2016-08-15/proxy/service-name/func-name/path-with-%20-space/action?x=1&a=2&x=3&with%20space=foo%20bar

// After URL decoding:
/2016-08-15/proxy/service-name/func-name/path-with- -space/action?x=1&a=2&x=3&with space=foo bar

// CanonicalizedResource (params sorted alphabetically, separated by \n):
/2016-08-15/proxy/service-name/func-name/path-with- -space/action\na=2\nwith space=foo bar\nx=1\nx=3

Example — Common request:

// CanonicalizedResource (query string discarded):
/2016-08-15/service-name/func-name/path-with- -space/action

Pseudocode reference

The following pseudocode shows how to build the string-to-sign and compute the signature. Use your AccessKey secret as the signing key.

// Build the string-to-sign
function composeStringToSign(method, path, headers, queries) {
    var contentMD5 = headers['content-md5'] || '';
    var contentType = headers['content-type'] || '';
    var date = headers['date'];
    var signHeaders = buildCanonicalHeaders(headers, 'x-fc-');

    var u = url.parse(path);
    var pathUnescaped = decodeURIComponent(u.pathname);
    var str = `${method}\n${contentMD5}\n${contentType}\n${date}\n${signHeaders}${pathUnescaped}`;

    if (queries) {
        var params = [];
        Object.keys(queries).forEach(function (key) {
            var values = queries[key];
            var type = typeof values;
            if (type === 'string') {
                params.push(`${key}=${values}`);
                return;
            }
            if (type === 'object' && values instanceof Array) {
                queries[key].forEach(function (value) {
                    params.push(`${key}=${value}`);
                });
            }
        });
        params.sort();
        str += '\n' + params.join('\n');
    }
    return str;
}

// Compute the signature using HMAC-SHA256 and Base64-encode the result
function signString(source, secret) {
    const buff = crypto.createHmac('sha256', secret)
        .update(source, 'utf8')
        .digest();
    return new Buffer(buff, 'binary').toString('base64');
}

After computing the signature, construct the Authorization header:

Authorization = "FC " + accessKeyID + ":" + signature

Example `Authorization` header value:

FC <your-access-key-id>:<computed-signature>

Replace <your-access-key-id> with your AccessKey ID and <computed-signature> with the Base64-encoded HMAC-SHA256 output.