You can specify the Authorization header in an HTTP request and include a signature in the value of this header to indicate that the request is authorized.

SDK implementation

Requests initiated by using OSS SDKs are automatically signed. You do not need to manually add signatures to the requests. For more information about how OSS SDKs for different programming languages sign requests, see the sample code of the OSS SDKs. The following table describes the sample code used to sign requests by OSS SDKs for different programming languages.
SDK Sample code
OSS SDK for Java OSSRequestSigner.java
OSS SDK for Python auth.py
OSS SDK for .Net OssRequestSigner.cs
OSS SDK for PHP OssClient.php
OSS SDK for C oss_auth.c
OSS SDK for JavaScript client.js
OSS SDK for Go auth.go
OSS SDK for Ruby util.rb
OSS SDK for iOS OSSModel.m
OSS SDK for Android OSSUtils.java

Calculation of the Authorization header

Authorization = "OSS " + AccessKeyId + ":" + Signature
Signature = base64(hmac-sha1(AccessKeySecret,
            VERB + "\n"
            + Content-MD5 + "\n" 
            + Content-Type + "\n" 
            + Date + "\n" 
            + CanonicalizedOSSHeaders
            + CanonicalizedResource))

Detail analysis:

  • AccessKeySecret indicates the AccessKey secret used to sign the request.
  • VERB indicates the method of the request to sign, such as PUT, GET, POST, HEAD, and DELETE.
  • \n indicates a line feed.
  • Content-MD5 indicates the MD5 hash of the request content. The value of Content-MD5 is a Base64-encoded 128-bit number that is calculated based on the content of the request message excluding request headers. Example: eB5eJF1ptWaXm4bijSPyxw==. This header can be used to check the validity of the request message. When OSS receives a request, OSS determines that the request is valid if the MD5 hash of the request message is the same as that of the request message that is sent. This header can be empty. For more information, visit RFC 2616 Content-MD5.
  • Content-Type indicates the type of the request content, such as application/octet-stream. This header can be empty.
  • Date indicates the time when this operation is performed, which must be in the GMT format, such as “Sun, 22 Nov 2015 08:16:38 GMT”.
  • CanonicalizedOSSHeaders indicates an assembly of HTTP headers prefixed with x-oss- in the alphabetical order.
  • CanonicalizedResource indicates the OSS resources you want to access.
Note The values of Date and CanonicalizedResource must be specified. If the difference between the time specified by the Date header in a request and the time on the server when the request is received is greater than 15 minutes, OSS rejects the request and returns HTTP status code 403.

Creation of CanonicalizedOSSHeaders

All HTTP headers prefixed with x-oss- are called CanonicalizedOSSHeaders. You can perform the following steps to create CanonicalizedOSSHeaders:

  1. Convert the names of all HTTP request headers prefixed with x-oss- into lowercase letters. For example, convert X-OSS-Meta-Name: TaoBao to x-oss-meta-name: TaoBao.
  2. If the request is sent by using an AccessKey pair obtained from STS, you must add the obtained security-token value to the signature string in the x-oss-security-token:security-token format.
  3. Sort all HTTP request headers that are converted in Step 1 in alphabetical order.
  4. Delete all spaces on each side of the delimiter between each header and its value. For example, convert x-oss-meta-name: TaoBao into x-oss-meta-name:TaoBao.
  5. Separate all headers with the \n delimiter to create CanonicalizedOSSHeaders.
Note
  • CanonicalizedOSSHeaders can be left empty. In this case, the \n delimiter at the end can be removed.
  • If CanonicalizedOSSHeaders includes only one header, the \n delimiter must be added at the end of the header. Example: x-oss-meta-a\n
  • If CanonicalizedOSSHeaders includes multiple headers, the \n delimiter must be added at the end of each header. Example: x-oss-meta-a:a\nx-oss-meta-b:b\nx-oss-meta-c:c\n.

Creation of CanonicalizedResource

The OSS resources that you send requests to access are called CanonicalizedResource. You can perform the following operations to create CanonicalizedResource:

  1. Set CanonicalizedResource to an empty string "".
  2. Specify the OSS resource you want to access in the following format: /BucketName/ObjectName. If you want to access a bucket but not a specific object, set CanonicalizedResource in the following format: /BucketName/. If you do not want to specify the resource you want to access, set CanonicalizedResource to a forward slash (/).
  3. If the resource that you want to access contains subresources, sort all subresources in alphabetical order and separate them with the ampersand (& ) delimiter. Add a question mark (?) and the subresource string to the end of the CanonicalizedResource string. In this example, the created CanonicalizedResource is in the following format: /BucketName/ObjectName?acl&uploadId=UploadId.
    • OSS supports the following subresources: acl, uploads, location, cors, logging, website, referer, lifecycle, delete, append, tagging, objectMeta, uploadId, partNumber, security-token, position, img, style, styleName, replication, replicationProgress, replicationLocation, cname, bucketInfo, comp, qos, live, status, vod, startTime, endTime, symlink, x-oss-process, response-content-type, response-content-language, response-expires, response-cache-control, response-content-disposition, and response-content-encoding.
    • You can specify the following three types of subresources:
      • Resource identifiers such as acl, append, uploadId, and symlink. For more information, see Bucket operations and Object operations.
      • Subresources that specify the response header fields, such as response-***. For more information, see the Request parameters section in GetObject.
      • Object processing methods such as x-oss-process. For more information, see Image Processing.

Calculation of the signature

  • The signature string used to calculate the signature must be UTF-8-encoded. A signature string that contains Chinese characters must be encoded in UTF-8. The encoded string is used together with AccessKeySecret to calculate the signature.
  • The HMAC-SHA1 method defined in RFC 2104 is used to calculate the signature. In this method, the Key is AccessKeySecret.
  • Content-Type and Content-MD5 can be left unspecified in a request. However, if OSS needs to verify the signature of the request, the values of these two headers must be replaced by line feeds (\n).
  • Non-standard HTTP headers prefixed with x-oss- must be added to the signature string. Other non-standard HTTP headers are ignored by OSS. For example, the x-oss-magic header in the following example must be included in the signature string.
    Note Headers prefixed with x-oss- in the signature string must comply with the following conventions:
    • The header names must be in lowercase.
    • The headers must be sorted in alphabetical order.
    • No space exists before or after the colon (:) that separates the header name and value.
    • Each header is followed by a line feed (\n). If no header is specified, set CanonicalizedOSSHeaders to null.

Example

Request Formula Signature string
PUT /nelson HTTP/1.0 Content-MD5: eB5eJF1ptWaXm4bijSPyxw== Content-Type: text/html Date: Thu, 17 Nov 2005 18:49:58 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com X-OSS-Meta-Author: foo@bar.com X-OSS-Magic: abracadabra Signature = base64(hmac-sha1(AccessKeySecret,VERB + "\n" + Content-MD5 + "\n"+ Content-Type + "\n" + Date + "\n" + CanonicalizedOSSHeaders+ CanonicalizedResource)) "PUT\n eB5eJF1ptWaXm4bijSPyxw==\n text/html\n Thu, 17 Nov 2005 18:49:58 GMT\n x-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson

If AccessKeyId is set to "44CF959******252F707" and AccessKeySecret is set to "OtxrzxIsfpFjA7Sw******8Bw21TLhquhboDYROV", you can run the following Python code to calculate the signature:

import hmac
import hashlib
h = hmac.new(oss2.to_bytes("OtxrzxIsfpFjA7Sw******8Bw21TLhquhboDYROV"),
             oss2.to_bytes("PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM=\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson"), hashlib.sha1)
signature = oss2.utils.b64encode_as_string(h.digest())
print("Signature: %s" % signature)

The calculated signature is 26NBxoKd******Dv6inkoDft/yA=. Therefore, the value of the Authorization header is OSS 44CF95900***BF252F707:26NBxoKd******Dv6inkoDft/yA=, which is in the following format: "OSS"+ AccessKeyId + ":" + Signature. The following example shows the final request that includes the Authorization header:

PUT /nelson HTTP/1.0
Authorization:OSS 44CF95900***BF252F707:26NBxoKd******Dv6inkoDft/yA=
Content-Md5: eB5eJF1ptWaXm4bijSPyxw==
Content-Type: text/html
Date: Thu, 17 Nov 2005 18:49:58 GMT
Host: oss-example.oss-cn-hangzhou.aliyuncs.com
X-OSS-Meta-Author: foo@bar.com
X-OSS-Magic: abracadabra

Detail analysis:

  • If the specified AccessKey ID does not exist or is not activated, 403 Forbidden is returned with the InvalidAccessKeyId error code.
  • If the format of the Authorization header is invalid, 400 Bad Request is returned with the InvalidArgument error code.
  • The date and time specified in all OSS requests must be in the GMT format defined in HTTP 1.1, in which date is in the following format:
    date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)
    Note In the preceding format, the day field is a 2-digit number. Therefore, "Jun 2", "2 Jun 1982", and "2-Jun-1982" are all invalid date formats.
  • If the Date header is not specified or is in an invalid format in a signed request, 403 Forbidden is returned with the AccessDenied error code.
  • If the difference between the time specified by the Date header in a request and the time on the server when the request is received is greater than 15 minutes, 403 Forbidden is returned with the RequestTimeTooSkewed error code.
  • If the specified AccessKey ID is activated but OSS determines that the signature in a request is incorrect, OSS returns 403 Forbidden and the correct signature string for verification and encryption in the response. You can check whether the signature string is correct based on the response.
    Sample response
    <?xml version="1.0" ?>
    <Error>
     <Code>
         SignatureDoesNotMatch
     </Code>
     <Message>
         The request signature we calculated does not match the signature you provided. Check your key and signing method.
     </Message>
     <StringToSignBytes>
         47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c
     </StringToSignBytes>
     <RequestId>
         1E446260FF9B****
     </RequestId>
     <HostId>
         oss-cn-hangzhou.aliyuncs.***
     </HostId>
     <SignatureProvided>
         y5H7yzPsA/tP4+0tH1HHvPEwUv8=
     </SignatureProvided>
     <StringToSign>
         GET
    Wed, 11 May 2011 07:59:25 GMT
    /oss-example?acl
     </StringToSign>
     <OSSAccessKeyId>
         AKIAIVAKMSMOY7VO****
     </OSSAccessKeyId>
    </Error>

Calculation of Content-MD5

The following examples use a string "123456789" to show how to calculate the Content-MD5 value of the request content:

  • Correct calculation
    1. Calculate the MD5 hash of the string, which is a 128-bit binary array.
    2. Encode the binary array (instead of the 32-bit string) in Base64.
    The following Python code provides an example on how to calculate the Content-MD5 value of the string "123456789":
    >>> import base64,hashlib
    >>> hash = hashlib.md5()
    >>> hash.update("0123456789")   // If you use Python 3, change the code to hash.update(b"0123456789"). 
    >>> base64.b64encode(hash.digest())
    'eB5eJF1ptWaXm4bijSPyxw=='

    Call hash.digest() to calculate the 128-bit binary array.

    >>> hash.digest()
    'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7'
  • Incorrect calculation
    Note A common incorrect operation is to encode the calculated 32-bit string in Base64 to obtain the Content-MD5 value.
    # Call hash.hexdigest() to obtain a 32-bit plaintext string. 
    >>> hash.hexdigest()
    '781e5e245d69b566979b86e28d23f2c7'
    # The following code provides an example of encoding the incorrect MD5 hash in Base64:
    >>> base64.b64encode(hash.hexdigest())
    'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='