All Products
Search
Document Center

Object Storage Service:(Recommended) Include a V4 signature in a URL

Last Updated:May 16, 2025

In addition to using the HTTP Authorization header for providing authentication information, you can use query string parameters to authenticate requests when you want to use a presigned URL to express a request. This way, you can grant users temporary access permissions on specific Object Storage Service (OSS) resources without exposing your access credentials. This topic describes how to include a V4 signature in a URL.

Use OSS SDKs to automatically implement V4 signatures

OSS SDKs support the automatic implementation of V4 signatures. We recommend that you use OSS SDKs to initiate requests. This eliminates the need to manually calculate signatures. For more information about the signature implementation for a specific programming language, see the sample code of OSS SDK for that programming language. The following table provides references to the sample code used to sign requests by using the V4 signature algorithm when you use OSS SDKs for different programming languages.

SDK

Example

Sample code

Java

Configure an OSSClient instance

OSSV4Signer.java

PHP

Configure an OSSClient instance

SignerV4.php

Node.js

Initialization

signatureUrlV4.js

Browser.js

Initialization

Python

Configure an OSSClient instance

v4.py

Go

Configure an OSSClient instance

v4.go

C++

Initialization

SignerV4.cc

C

Initialization

oss_auth.c

URL signing

  • Example

    https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject?x-oss-additional-headers=host&x-oss-credential=LTAI********************%2F20241203%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-date=20241203T034420Z&x-oss-expires=86400&x-oss-signature=70c542eaf652ac291c0c343d63ac24ede41c0526661d9d4c63c0906a2686160c&x-oss-signature-version=OSS4-HMAC-SHA256

    For readability, the fields in the x-oss-credential parameter in the preceding URL are separated by forward slashes (/). When you initiate a request, URI-encode the forward slashes (/) in the URL to convert them into %2F. Example:

    &x-oss-credential=LTAI********************%2F20241203%2Fcn-hangzhou%2Foss%2Faliyun_v4_request
  • Query string parameters

    Parameter

    Type

    Required

    Example

    Description

    x-oss-signature-version

    String

    Yes

    OSS4-HMAC-SHA256

    The version and algorithm of the signature. Set the value to OSS4-HMAC-SHA256.

    x-oss-credential

    String

    Yes

    LTAI********************/20241203/cn-hangzhou/oss/aliyun_v4_request

    The credentials that you can use to calculate the signature. Format:

    LTAI********************/<date>/<region>/oss/aliyun_v4_request
    • AccessKeyId: the AccessKey ID in the AccessKey pair.

    • date: the date when the request was initiated.

    • region: the region in which the requested resource resides.

    • oss: the name of the requested service. Set the value to oss.

    • aliyun_v4_request: the description of the signature version in the request. Set the value to aliyun_v4_request.

    x-oss-date

    String

    Yes

    20241203T034420Z

    The time when the URL was signed. The time follows the ISO 8601 standard and is displayed in UTC.

    Note

    The time is used as the timestamp for the string to sign. The value must be the same as that of the date field in the derived signing key.

    x-oss-expires

    Integer

    Yes

    3600

    The validity period of the signed URL. The valid period is calculated from the value of the x-oss-date parameter. Unit: seconds.

    • The validity period of a signed URL generated by using an AccessKey pair must meet the following requirements: Minimum value: 1. Maximum value: 604,800 seconds (7 days).

    • The validity period of a signed URL generated by using temporary access credentials obtained from Security Token Service (STS) must meet the following requirements: Minimum value: 1. Maximum value: 43,200 seconds (12 hours).

    Note

    The point in time when OSS receives the request (T) must meet the following requirement: (x-oss-date − 15 minutes) ≤ T ≤ (x-oss-date + x-oss-expires).

    • If T is earlier than the value (x-oss-date − 15 minutes), the request is invalid.

    • If the current time is later than the value (x-oss-date + x-oss-expires), the request is invalid.

    x-oss-additional-headers

    String

    No

    host

    The headers that you want to add to calculate the signature. For example, you can add the host header to prevent the domain name from which the request is initiated from being changed.

    The following items describe the requirements for constructing a header:

    • All headers in the x-oss-additional-headers parameter must be in lowercase letters.

    • All headers in the x-oss-additional-headers parameter must be sorted in alphabetical order.

    • All headers in an array are separated by semicolons (;) to obtain a string.

    x-oss-signature

    String

    Yes

    77Dv****************

    The description of the signature verification. The x-oss-signature parameter is not included in the signature calculation.

    x-oss-security-token

    String

    No

    CAIS********************************

    The security token issued by STS. This parameter is required only when you use a security token to calculate a signature for the URL.

Signature calculation process

image

The method used to calculate a signature for a URL is similar to the method used to calculate a signature for the Authorization header. The following items describe the differences between the two methods:

  • The x-oss-content-sha256 header that describes a payload hash is not used to calculate a signature for a URL. When you create a signed URL, you cannot evaluate the payload content. Instead, UNSIGNED-PAYLOAD is used.

  • If a key in the query string parameters of a signed URL is the same as a header to be signed but their values are different, an error is reported. If a key has multiple values, all values of the key are compared at the same time. If the values are different, an error is reported.

  • If you use the temporary access credentials obtained from STS to access OSS resources in a signed URL, you must add the x-oss-security-token parameter to the query string of the URL.

  • The x-oss-signature parameter in the query string is not included in the signature calculation.

Step 1: Create a canonical request

Convert the content of your request to the canonical format.

Format

HTTP Verb + "\n" +
Canonical URI + "\n" +
Canonical Query String + "\n" +
Canonical Headers + "\n" +
Additional Headers + "\n" +
Hashed PayLoad

The following table describes the preceding parameters.

Parameter

Type

Required

Example

Description

HTTP Verb

Enumeration

Yes

GET

The HTTP method, which can be PUT, GET, POST, HEAD, DELETE, or OPTIONS.

Note

Canonical URI

String

Yes

/examplebucket/exampleobject

A URI-encoded string. Encode all characters except for the forward slash (/) in the absolute path.

  • The URI starts with a forward slash (/) that follows the domain name up to the end of the string if query string parameters are not included.

  • The URI starts with a forward slash (/) that follows the domain name and ends with a question mark (?) if query string parameters are included.

The following items describe how to specify a canonical URI based on the resources included in the request URI:

  • If the request URI contains both a bucket name and an object name, the canonical URI is in the following format:

    /examplebucket/exampleobject.

  • If the request URI contains only a bucket name, the canonical URI is in the following format: /examplebucket/.

  • If the request URI contains only an object name, the canonical URI is set to /.

Canonical Query String

String

Yes

UriEncode("marker") + "=" + UriEncode("someMarker") + "&" + UriEncode("max-keys") + "=" + UriEncode("20") + "&" + UriEncode("prefix") + "=" + UriEncode("somePrefix")

The URI-encoded query string parameters. You must URI-encode each key and value individually.

  • Sort the parameters in the canonical query string in alphabetical order by key name after you encode the parameters. If identical keys exist, sort the keys in chronological order based on the time when they were added.

  • If a key does not have a value, add only the key.

  • If a request does not include a query string, set the canonical query string to an empty string (""). You must add a line feed at the end.

  • If a key in the query string parameters of a signed URL is the same as a header to be signed but their values are different, an error is reported. If a key has multiple values, all values of the key are compared at the same time. If the values are different, an error is reported.

Canonical Headers

String

Yes

host:

examplebucket.oss-cn-hangzhou.aliyuncs.com

x-oss-content-sha256:

eee300fa39f52127a02af5f9bb86c0fd8b6776fc19101d9a6a7982c9d0edcc04

x-oss-date:

20241203T034420Z

A string obtained by converting the list of request headers to the canonical format. Add a line feed at the end of the string.

  • A header key and value are separated by a colon (:), and headers are separated by a line feed.

  • Header keys must be in lowercase letters and sorted in alphabetical order. Leading or trailing spaces in the header values must be trimmed.

  • Header keys are sorted in alphabetical order.

  • The request time is specified by the x-oss-date header. The time follows the ISO 8601 standard and is displayed in UTC. Example: 20241203T034420Z.

  • The x-oss-content-sha256 header that describes a payload hash is not used to calculate a signature for a URL. When you create a signed URL, you cannot evaluate the payload content. Instead, UNSIGNED-PAYLOAD is used.

Canonical Headers are divided into two types:

  • The headers specified by Additional Headers and used for signature calculation

  • Headers that must be added to Canonical Headers if they are in the request:

    • Content-Type

    • Content-MD5

    • x-oss-*

Additional Headers

String

Yes

content-length;host

The headers that you want to add to calculate the signature. All header keys must be in lowercase and sorted in alphabetical order.

Hashed PayLoad

String

Yes

UNSIGNED-PAYLOAD

Valid value: UNSIGNED-PAYLOAD.

Example

"GET" | "GET" | ... + "\n" +
UriEncode(<Resource>) + "\n" +
UriEncode(<QueryParam1>) + "=" + UriEncode(<Value>) + "&" + UriEncode(<QueryParam2>) + "\n" +
Lowercase(<HeaderName1>) + ":" + Trim(<value>) + "\n" + Lowercase(<HeaderName2>) + ":" + Trim(<value>) + "\n" + "\n"
Lowercase(<AdditionalHeaderName1>) + ";" + Lowercase(<AdditionalHeaderName2>) + "\n" +
UNSIGNED-PAYLOAD

Step 2: Create a string to sign

Concatenate the following strings to create a string to sign.

Format

"OSS4-HMAC-SHA256" + "\n" +
dateTimeStr + "\n" +
dateStr + "\n" +
DigestUtils.sha256Hex(canonicalRequest);

Example

String stringToSign = "OSS4-HMAC-SHA256\n" +
                dateTimeStr + "\n" +
                dateStr + "/cn-hangzhou/oss/aliyun_v4_request\n" +
                DigestUtils.sha256Hex(canonicalRequest);

The following table describes the parameters.

Parameter

Type

Required

Sample file

Description

OSS4-HMAC-SHA256

Enumeration

Yes

OSS4-HMAC-SHA256

The algorithm used to create the hash of the canonical request. Set the value to OSS4-HMAC-SHA256.

dateTimeStr

String

Yes

20241203T034420Z

The current time in UTC. The time must follow the ISO 8601 standard.

dateStr

String

Yes

20241203/cn-hangzhou/oss/aliyun_v4_request

The scope information. This restricts the calculated signature to the specified region and service. Format:

<SignDate>/<Region>/oss/aliyun_v4_request

  • SignDate: the date when the request is initiated.

  • Region: the region in which the requested resource resides.

  • oss: the name of the requested service. Set the value to oss.

  • aliyun_v4_request: the description of the signature version in the request. Set the value to aliyun_v4_request.

CanonicalRequest

String

Yes

GET

/examplebucket/exampleobject

x-oss-additional-headers=host&x-oss-credential=LTAI********************%2F20241203%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-date=20241203T034420Z&x-oss-expires=86400&x-oss-signature-version=OSS4-HMAC-SHA256

host:examplebucket.oss-cn-hangzhou.aliyuncs.com

host

UNSIGNED-PAYLOAD

The string created in Step 1.

Step 3: Calculate the signature

Create a signing key and use the signing key to calculate the signature.

  1. Calculate the signing key.

    HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("aliyun_v4" + accesskeysecret).getBytes(), dateStr), Region), "oss"), "aliyun_v4_request");
  2. Calculate the signature.

    BinaryUtil.toHex(HMAC-SHA256(SigningKey, StringToSign))

Complete sample code used to obtain a V4 signed URL

The following sample code provides an example on how to use OSS SDK for Java to calculate a V4 signed URL. The signed URL can be used only to download and access objects.

Important

When you use the following sample code, you must replace the variables with the actual values. For example, replace Canonical URI with /examplebucket/exampleobject and Region with cn-hangzhou.

import com.aliyun.oss.common.utils.BinaryUtil;
import org.apache.commons.codec.digest.DigestUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;

public class Demo {

    /**
     * Signature calculation tool
     *
     * @return url
     */
    public static void main(String[] args) throws Exception {
        // Before you run the sample code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are configured. 
        String accesskeyid =  System.getenv().get("OSS_ACCESS_KEY_ID");
        String accesskeysecret =  System.getenv().get("OSS_ACCESS_KEY_SECRET");
        // Query and display the current time. The time follows the ISO 8601 standard and is displayed in UTC.
        ZonedDateTime now = ZonedDateTime.now(TimeZone.getTimeZone("UTC").toZoneId());
        String dateStr = now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String dateTimeStr = now.format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
        // Step 1: Create a canonical request. 
        String canonicalRequest =
                "GET\n" +
                        "/examplebucket/exampleobject\n" +
                        "x-oss-additional-headers=host&x-oss-credential=" + accesskeyid + "%2F" + dateStr + "%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-date=" + dateTimeStr + "&x-oss-expires=86400&x-oss-signature-version=OSS4-HMAC-SHA256\n" +
                        "host:examplebucket.oss-cn-hangzhou.aliyuncs.com\n" +
                        "\n" +
                        "host\n" +
                        "UNSIGNED-PAYLOAD";
        System.out.println("canonicalRequest:" + canonicalRequest);
        // Step 2: Create a string to sign. 
        String stringToSign = "OSS4-HMAC-SHA256\n" +
                dateTimeStr + "\n" +
                dateStr + "/cn-hangzhou/oss/aliyun_v4_request\n" +
                DigestUtils.sha256Hex(canonicalRequest);

        // Step 3: Calculate the signature. 
        byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), dateStr);
        byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou");
        byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
        byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");

        byte[] result = hmacsha256(signingKey, stringToSign);
        String signature = BinaryUtil.toHex(result);
        System.out.println("signature:" + signature);

        // Step 4: Add the signature to the URL. 
        String resourcePath = "exampleobject";
        String endpoint = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com";
        String queryString = "x-oss-additional-headers=host&" +
                "x-oss-credential=" + accesskeyid + "%2F" + dateStr + "%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&" +
                "x-oss-date=" + dateTimeStr + "&" +
                "x-oss-expires=86400&" +
                "x-oss-signature=" + signature + "&" +
                "x-oss-signature-version=OSS4-HMAC-SHA256";

        String urlStr = endpoint + "/" + resourcePath + "?" + queryString;
        URL url = new URL(urlStr);
        System.out.println("url:" + url);
    }

    public static byte[] hmacsha256(byte[] key, String data) {
        try {
            // Initialize the HMAC key specifications, set the algorithm to HMAC-SHA256, and use the provided key. 
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");

            // Obtain a Mac instance and use the getInstance method to set the algorithm to HMAC-SHA256. 
            Mac mac = Mac.getInstance("HmacSHA256");
            // Use the key to initialize the Mac instance. 
            mac.init(secretKeySpec);

            // Calculate the HMAC value. Use the doFinal method to receive the data to be calculated and return the calculation results in arrays. 
            byte[] hmacBytes = mac.doFinal(data.getBytes());

            return hmacBytes;
        } catch (Exception e) {
            throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
        }
    }
}

Sample output:

signature:eee300fa39f52127a02af5f9bb86c0fd8b6776fc19101d9a6a7982c9d0edcc04
url:https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject?x-oss-additional-headers=host&x-oss-credential=LTAI********************%2F20241203%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-date=20241203T032307Z&x-oss-expires=86400&x-oss-signature=eee300fa39f52127a02af5f9bb86c0fd8b6776fc19101d9a6a7982c9d0edcc04&x-oss-signature-version=OSS4-HMAC-SHA256

References