All Products
Search
Document Center

Object Storage Service:POST V4 signature

Last Updated:May 27, 2026

OSS requires a V4 signature in each PostObject request to verify authenticity. Your application server derives the signature from request parameters (policy, expiration) using your AccessKey Secret and HMAC-SHA256. OSS rejects any request with an invalid signature.

How POST signatures work

POST requests use the V4 signature algorithm. The form and policy together ensure request authenticity.

Form elements

A form transmits the file and metadata in a POST request. The following table describes V4-specific form elements. Common form elements are listed in PostObject form elements.

Parameter

Type

Required

Description

x-oss-signature-version

String

Yes

The signature version and algorithm. The value is fixed to OSS4-HMAC-SHA256.

x-oss-credential

String

Yes

Specifies the parameter set for the derived key. The format is as follows:

<AccessKeyId>/<date>/<region>/oss/aliyun_v4_request
  • AccessKeyId: Your AccessKey ID.

  • date: The date of the request in the YYYYMMDD format. For example, 20231203.

  • region: The general-purpose Alibaba Cloud region ID. Example: cn-hangzhou.

  • oss: The requested service name. The value is fixed to oss.

  • aliyun_v4_request: The request version. The value is fixed to aliyun_v4_request.

x-oss-date

String

Yes

The request time in ISO 8601 format. Example: 20231203T121212Z.

  • A 15-minute backward time skew is allowed for the x-oss-date field to account for network delays and clock drift.

  • A request is valid for a maximum of 7 days from the x-oss-date value. OSS rejects requests where x-oss-date is older than 7 days to prevent replay attacks.

  • The x-oss-date value serves as the TimeStamp in StringToSign. It must fall on the same day as the Date in the signing key and match the x-oss-date value in the policy.

x-oss-signature

String

Yes

The HMAC-SHA256 hash of the Base64-encoded policy, represented as a hexadecimal string.

Policy

The policy is a JSON object that constrains file uploads by specifying allowed bucket names, object prefixes, expiration times, HTTP methods, content sizes, and content types.

Important

A policy must include expiration and conditions. The x-oss-security-token condition in this example is required only when using STS temporary credentials. Omit it when using a long-term AccessKey.

{
  "expiration": "2023-12-03T13:00:00.000Z",
  "conditions": [
    {"bucket": "examplebucket"},
    {"x-oss-signature-version": "OSS4-HMAC-SHA256"},
    {"x-oss-credential": "AKIDEXAMPLE/20231203/cn-hangzhou/oss/aliyun_v4_request"},
    {"x-oss-security-token": "CAIS******"},
    {"x-oss-date": "20231203T121212Z"},
    ["content-length-range", 1, 10],
    ["eq", "$success_action_status", "201"],
    ["starts-with", "$key", "user/eric/"],
    ["in", "$content-type", ["image/jpg", "image/png"]],
    ["not-in", "$cache-control", ["no-cache"]]
  ]
}

The policy parameters are described as follows:

  • expiration

    The expiration time of the policy in ISO 8601 GMT format. Example: 2023-12-03T13:00:00.000Z means the POST request must be sent before 13:00:00 UTC on December 3, 2023.

  • conditions

    Defines conditions for form fields in the POST request.

    Parameter

    Type

    Required

    Description

    Matching type

    bucket

    String

    No

    The bucket name.

    bucket

    x-oss-signature-version

    String

    Yes

    The signature version and algorithm. The value is fixed to OSS4-HMAC-SHA256.

    x-oss-signature-version

    x-oss-credential

    String

    Yes

    Specifies the parameter set for the derived key. The format is as follows:

    <AccessKeyId>/<date>/<region>/oss/aliyun_v4_request
    • AccessKeyId: Your AccessKey ID.

    • date: The request date.

    • region: The general-purpose Alibaba Cloud region ID. Example: cn-hangzhou.

    • oss: The requested service name. The value is fixed to oss.

    • aliyun_v4_request: The request version. The value is fixed to aliyun_v4_request.

    x-oss-credential

    x-oss-security-token

    String

    No

    Required only when using STS temporary credentials. Obtain a token by calling the AssumeRole operation.

    x-oss-security-token

    x-oss-date

    String

    Yes

    The request time in ISO 8601 format. Example: 20231203T121212Z.

    • A 15-minute backward time skew is allowed for the x-oss-date header to account for network delays and clock drift.

    • A request is valid for a maximum of 7 days from the x-oss-date value. OSS rejects requests where x-oss-date is expired to prevent replay attacks.

    • The x-oss-date value serves as the TimeStamp in StringToSign. It must fall on the same day as the Date in the signing key and match the x-oss-date value in the policy.

    x-oss-date

    content-length-range

    String

    No

    The minimum and maximum allowed size of the object to upload, in bytes.

    content-length-range

    success_action_status

    String

    No

    The HTTP status code to return after a successful upload.

    eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci

    key

    String

    No

    The name of the object to upload.

    eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci

    content-type

    String

    No

    Restricts the file type of the upload.

    eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci

    cache-control

    String

    No

    Specifies the caching behavior of the object.

    eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci

Matching types for conditions

Matching type

Description

content-length-range

Specifies the allowed minimum and maximum size of the file to upload. For example, to allow file sizes from 1 to 10 bytes, use ["content-length-range", 1, 10].

eq

The form field value must exactly match the specified value. For example, to require the key field to be exactly "a", use ["eq", "$key", "a"].

starts-with

The form field value must start with the specified prefix. For example, to require the key value to start with "user/user1", use ["starts-with", "$key", "user/user1"].

in

Specifies a list of values that the form field is allowed to have. For example, to verify that an uploaded image is a JPG or PNG, use ["in", "$content-type", ["image/jpg", "image/png"]].

not-in

Specifies a list of values that the form field is not allowed to have. For example, to disallow the "no-cache" value for cache-control, use ["not-in", "$cache-control", ["no-cache"]].

eq-ci

The form field value must exactly match the specified value, ignoring case. The comparison is performed on lowercase strings. For example, with ["eq-ci", "$key", "AbC"], object names such as "abc", "ABC", and "aBc" are all valid matches.

starts-with-ci

The form field value must start with the specified prefix, ignoring case. The comparison is performed on lowercase strings. For example, with ["starts-with-ci", "$key", "User/"], values starting with "user/", "USER/", or "User/" are all valid matches.

in-ci

Specifies a list of allowed values, ignoring case. The comparison is performed on lowercase strings. For example, with ["in-ci", "$content-type", ["IMAGE/JPG", "image/PNG"]], values such as "image/jpg" and "IMAGE/PNG" are both valid matches.

not-in-ci

Specifies a list of disallowed values, ignoring case. The comparison is performed on lowercase strings. For example, with ["not-in-ci", "$cache-control", ["No-Cache"]], values such as "no-cache", "NO-CACHE", and "No-Cache" are all excluded.

Note

When conditions contain multiple statements for the same form field (such as in and not-in), the last statement takes precedence. Avoid conflicting conditions for the same field.

Escape characters for a policy

In a policy, the dollar sign ($) indicates a variable. Use \$ for a literal dollar sign. The following table lists escape characters for policy JSON.

Escape character

Description

\/

Forward slash

\\

Backslash

\

Double quotation mark

\$

Dollar sign

\b

Space

\f

Form feed

\n

Line break

\r

Carriage return

\t

Horizontal tab

\uxxxx

Unicode character

Signature calculation process

  1. Create a UTF-8 encoded policy.

  2. Construct the string to sign.

    Base64-encode the policy. The result is the string to sign.

  3. Calculate the signing key.

    Derive a signing key by applying successive HMAC-SHA256 operations using your AccessKey Secret, date, region, and service name.

  4. Calculate the signature.

    HMAC-SHA256 sign the string to sign with the signing key, then convert the result to a hexadecimal string. This is the final signature.

image

POST signature calculation examples

  1. The following Java example calculates a POST signature for the policy above.

    AccessKey credentials

    import com.aliyun.oss.common.utils.BinaryUtil;
    import org.apache.commons.codec.binary.Base64;
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import com.fasterxml.jackson.databind.ObjectMapper; 
    import java.util.Map; 
    import java.util.HashMap; 
    import java.util.List; 
    import java.util.ArrayList; 
    import java.util.Arrays; 
    
    public class Demo {
        public static void main(String[] args) throws Exception {
            // Before you run this code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
            String accesskeyid =  System.getenv().get("OSS_ACCESS_KEY_ID");
            String accesskeysecret =  System.getenv().get("OSS_ACCESS_KEY_SECRET");
    
            // Step 1: Create a policy.
            ObjectMapper mapper = new ObjectMapper();
    
            Map<String, Object> policy = new HashMap<>();
            policy.put("expiration", "2024-12-03T13:00:00.000Z");
    
            List<Object> conditions = new ArrayList<>();
    
            Map<String, String> bucketCondition = new HashMap<>();
            bucketCondition.put("bucket", "examplebucket");
            conditions.add(bucketCondition);
    
            Map<String, String> signatureVersionCondition = new HashMap<>();
            signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
            conditions.add(signatureVersionCondition);
    
            Map<String, String> credentialCondition = new HashMap<>();
            credentialCondition.put("x-oss-credential", accesskeyid + "/20241203/cn-hangzhou/oss/aliyun_v4_request");
            conditions.add(credentialCondition);
    
            Map<String, String> dateCondition = new HashMap<>();
            dateCondition.put("x-oss-date", "20241203T121212Z");
            conditions.add(dateCondition);
    
            conditions.add(Arrays.asList("content-length-range", 1, 10));
            conditions.add(Arrays.asList("eq", "$success_action_status", "201"));
            conditions.add(Arrays.asList("starts-with", "$key", "user/eric/"));
            conditions.add(Arrays.asList("in", "$content-type", Arrays.asList("image/jpg", "image/png")));
            conditions.add(Arrays.asList("not-in", "$cache-control", Arrays.asList("no-cache")));
    
            policy.put("conditions", conditions);
    
            String jsonPolicy = mapper.writeValueAsString(policy);
            // Step 2: Construct the string to sign.
            String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
            System.out.println(stringToSign);
            
            // Step 3: Calculate the signing key.
            byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), "20241203");
            byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou");
            byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
            byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
    
            // Step 4: Calculate the signature.
            byte[] result = hmacsha256(signingKey, stringToSign);
            String signature = BinaryUtil.toHex(result);
            System.out.println("signature:" + signature);
    
        }
    
        public static byte[] hmacsha256(byte[] key, String data) {
            try {
                // Initialize the HMAC key specification, specifying HmacSHA256 as the algorithm and using the provided key.
                SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
    
                // Get a Mac instance, specifying HmacSHA256 as the algorithm.
                Mac mac = Mac.getInstance("HmacSHA256");
                // Initialize the Mac object with the key.
                mac.init(secretKeySpec);
    
                // Perform the HMAC calculation. The doFinal method takes the data and returns the resulting hash as a byte array.
                byte[] hmacBytes = mac.doFinal(data.getBytes());
    
                return hmacBytes;
            } catch (Exception e) {
                throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
            }
        }
    }

    The following result is returned:

    signature:3908473f7dbfb79a102eaaa44ca1edec8d7058ce3bd1c624d59eb437463bd5d6

    Temporary access credentials

    When using temporary credentials from STS, obtain a security token by calling the AssumeRole operation.

    import com.aliyun.oss.common.utils.BinaryUtil;
    import org.apache.commons.codec.binary.Base64;
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import com.aliyun.sts20150401.models.AssumeRoleResponse;
    import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
    import com.aliyun.tea.TeaException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import java.util.*;
    public class Demo {
    
        // Initialize the STS client.
        public static com.aliyun.sts20150401.Client createStsClient() throws Exception {
            com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                    // Required. Make sure that the OSS_ACCESS_KEY_ID environment variable is set.
                    .setAccessKeyId(System.getenv("OSS_ACCESS_KEY_ID"))
                    // Required. Make sure that the OSS_ACCESS_KEY_SECRET environment variable is set.
                    .setAccessKeySecret(System.getenv("OSS_ACCESS_KEY_SECRET"));
            // Endpoint 
            config.endpoint = "sts.cn-hangzhou.aliyuncs.com";
            return new com.aliyun.sts20150401.Client(config);
        }
    
        // Obtain temporary access credentials from STS.
        public static AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials getCredential() throws Exception {
            com.aliyun.sts20150401.Client client = Demo.createStsClient();
            com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest()
                    // Required. Make sure that the OSS_STS_ROLE_ARN environment variable is set.
                    .setRoleArn(System.getenv("OSS_STS_ROLE_ARN"))
                    .setRoleSessionName("role_session_name");// Custom session name.
            com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
            try {
                // If you copy this code, print the API response on your own.
                AssumeRoleResponse response = client.assumeRoleWithOptions(assumeRoleRequest, runtime);
                // The credentials object contains the AccessKeyId, AccessKeySecret, and SecurityToken for subsequent operations.
                return response.body.credentials;
            } catch (TeaException error) {
                // This is for demonstration only. In a production environment, handle exceptions with care and do not ignore them.
                // Error message
                System.out.println(error.getMessage());
                // Troubleshooting URL
                System.out.println(error.getData().get("Recommend"));
                com.aliyun.teautil.Common.assertAsString(error.message);
            } catch (Exception _error) {
                TeaException error = new TeaException(_error.getMessage(), _error);
                // This is for demonstration only. In a production environment, handle exceptions with care and do not ignore them.
                // Error message
                System.out.println(error.getMessage());
                // Troubleshooting URL
                System.out.println(error.getData().get("Recommend"));
                com.aliyun.teautil.Common.assertAsString(error.message);
            }
            return null;
        }
    
        public static void main(String[] args) throws Exception {
    
            AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials sts_data = getCredential();
            String accesskeyid = sts_data.accessKeyId;
            String accesskeysecret = sts_data.accessKeySecret;
            String securitytoken = sts_data.securityToken;
            // Step 1: Create a policy.
            ObjectMapper mapper = new ObjectMapper();
    
            Map<String, Object> policy = new HashMap<>();
            policy.put("expiration", "2024-12-03T13:00:00.000Z");
    
            List<Object> conditions = new ArrayList<>();
    
            Map<String, String> bucketCondition = new HashMap<>();
            bucketCondition.put("bucket", "examplebucket");
            conditions.add(bucketCondition);
    
            Map<String, String> signatureVersionCondition = new HashMap<>();
            signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
            conditions.add(signatureVersionCondition);
            
            Map<String, String> securityTokenCondition = new HashMap<>();
            securityTokenCondition.put("x-oss-security-token", securitytoken);
            conditions.add(securityTokenCondition);
            
            Map<String, String> credentialCondition = new HashMap<>();
            credentialCondition.put("x-oss-credential", accesskeyid + "/20241203/cn-hangzhou/oss/aliyun_v4_request");
            conditions.add(credentialCondition);
    
            Map<String, String> dateCondition = new HashMap<>();
            dateCondition.put("x-oss-date", "20241203T121212Z");
            conditions.add(dateCondition);
    
            conditions.add(Arrays.asList("content-length-range", 1, 10));
            conditions.add(Arrays.asList("eq", "$success_action_status", "201"));
            conditions.add(Arrays.asList("starts-with", "$key", "user/eric/"));
            conditions.add(Arrays.asList("in", "$content-type", Arrays.asList("image/jpg", "image/png")));
            conditions.add(Arrays.asList("not-in", "$cache-control", Arrays.asList("no-cache")));
    
            policy.put("conditions", conditions);
    
            String jsonPolicy = mapper.writeValueAsString(policy);
            // Step 2: Construct the string to sign.
            String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
    
            // Step 3: Calculate the signing key.
            byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), "20241203");
            byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou");
            byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
            byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
    
            // Step 4: Calculate the signature.
            byte[] result = hmacsha256(signingKey, stringToSign);
            String signature = BinaryUtil.toHex(result);
            System.out.println("signature:" + signature);
    
        }
    
        public static byte[] hmacsha256(byte[] key, String data) {
            try {
                // Initialize the HMAC key specification, specifying HmacSHA256 as the algorithm and using the provided key.
                SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
    
                // Get a Mac instance, specifying HmacSHA256 as the algorithm.
                Mac mac = Mac.getInstance("HmacSHA256");
                // Initialize the Mac object with the key.
                mac.init(secretKeySpec);
    
                // Perform the HMAC calculation. The doFinal method takes the data and returns the resulting hash as a byte array.
                byte[] hmacBytes = mac.doFinal(data.getBytes());
    
                return hmacBytes;
            } catch (Exception e) {
                throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
            }
        }
    }

    The following result is returned:

    signature:1e09438f7ad01af6b3e144b42c98929c68f8d090ce07f4c277b18d8b62d0aa02
  2. The following Python example calculates a POST signature.

    import base64
    import hmac
    import hashlib
    import os
    
    def hmac_sha256(key, data):
        return hmac.new(key, data.encode('utf-8'), hashlib.sha256).digest()
    
    # Read the AccessKey ID and AccessKey Secret from environment variables.
    accesskeyid = os.getenv('OSS_ACCESS_KEY_ID')
    accesskeysecret = os.getenv('OSS_ACCESS_KEY_SECRET')
    
    # Print the AccessKey ID.
    print(accesskeyid)
    
    # Check if the environment variables were successfully retrieved.
    if not accesskeyid or not accesskeysecret:
        raise ValueError("Necessary environment variables not found: OSS_ACCESS_KEY_ID or OSS_ACCESS_KEY_SECRET")
    
    # Create the policy.
    policy = f'''{{
      "expiration": "2025-01-01T00:00:00.000Z",
      "conditions": [
        {{"x-oss-signature-version": "OSS4-HMAC-SHA256"}},
        {{"x-oss-credential": "{accesskeyid}/20241105/cn-hangzhou/oss/aliyun_v4_request"}},
        {{"x-oss-date": "20241105T065000Z"}}
      ]
    }}'''
    
    # Print the policy.
    print(policy)
    
    # Calculate the string to sign.
    string_to_sign = base64.b64encode(policy.encode('utf-8')).decode('utf-8')
    print(string_to_sign)
    
    # Calculate the signing key.
    date_key = hmac_sha256(f"aliyun_v4{accesskeysecret}".encode('utf-8'), "20241105")
    date_region_key = hmac_sha256(date_key, "cn-hangzhou")
    date_region_service_key = hmac_sha256(date_region_key, "oss")
    signing_key = hmac_sha256(date_region_service_key, "aliyun_v4_request")
    
    # Calculate the signature.
    result = hmac_sha256(signing_key, string_to_sign)
    signature = result.hex()
    print("signature:", signature)

    The following result is returned:

    signature:9e85d56429245283b1aca5bc2dc31e0020b95ac2de9e9b81b496994db602ba1e