This topic describes how to use a signed URL or a temporary access credential from Security Token Service (STS) to grant a third-party user permissions to upload objects directly to Object Storage Service (OSS).

Prerequisites

A bucket is created. For more information, see Create buckets.

Background information

In a standard client/server system architecture, the server is responsible for receiving and processing requests from the client, and OSS is used as a backend storage service. In that case, the client sends the objects to upload to the application server. Then, the server forwards the objects to OSS. In this process, objects are transmitted twice: from the client to the server and from the server to OSS. In the case of bursts of access requests, the server must provide sufficient bandwidth resources for multiple clients to upload objects simultaneously. This presents a challenge to the architecture scalability.

Benefits

To resolve this issue, OSS provides authorized third-party upload. This way, each client can upload objects directly to OSS without transmitting them to the server. This reduces the cost of application servers and maximizes the OSS capability to process large amounts of data. Furthermore, you can focus on your business without worries about bandwidth and concurrency limits.

You have the option to use a signed URL or a temporary access credential to grant a third-party user permissions to upload objects directly to OSS.

Temporary access credential

You can use Alibaba Cloud STS to authorize temporary access to OSS. STS is a web service that provides temporary access tokens for users. You can use STS to grant a set of temporary access credentials that have a custom validity period and custom permissions to a third-party application or a RAM user managed by you. For more information about STS, see What is STS?.

STS provides the following benefits:

  • You need only to generate an access token and send the access token to a third-party application, instead of exposing your AccessKey pair to the third-party application. You can define the access permissions and validity period of this token.
  • The token automatically expires after the validity period. Therefore, you do not need to manually revoke the access permissions of a token.
Note You can call the AssumeRole operation or use STS SDKs for various programming languages to obtain a temporary access credential. The temporary access credential contains a security token and a temporary AccessKey pair. The AccessKey pair consists of an AccessKey ID and an AccessKey secret. The minimum validity period of a temporary access credential is 900 seconds. The maximum validity period of a temporary access credential is the maximum session duration specified for the current role. For more information, see Specify the maximum session duration for a RAM role.

Use OSS SDK

The following code provides examples on how to use a temporary access credential to grant a third-party user permissions to directly upload objects to OSS by using OSS SDKs for common programming languages. For more information about how to use OSS SDKs for other programming languages to perform this operation, see Overview.

// Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// Specify the temporary AccessKey pair obtained from STS. 
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// Specify the security token obtained from STS. 
String securityToken = "yourSecurityToken";
// Specify the name of the bucket. Example: examplebucket. 
String bucketName = "examplebucket";
// Specify the full path of the object. The path cannot contain the bucket name. Example: exampledir/exampleobject.txt. 
String objectName = "exampledir/exampleobject.txt";

// You can use the AccessKey pair and security token contained in the temporary access credential obtained from STS to create an OSSClient. 
// Create an OSSClient instance. 
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

// Upload the object by using the temporary access credential that is obtained from STS. 
// Specify the full path of the local file to upload. By default, if you do not specify the local file, the local file is uploaded from the path of the project to which the sample program belongs. 
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File("D:\\localpath\\examplefile.txt"));
ossClient.putObject(putObjectRequest);

// Shut down the OSSClient instance. 
ossClient.shutdown();
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\OssClient;
use OSS\Core\OssException;

// Specify the temporary AccessKey ID and AccessKey secret that are obtained from STS. 
$accessKeyId = "yourAccessKeyId";
$accessKeySecret = "yourAccessKeySecret";
// Specify the security token that is obtained from STS. 
$securityToken = "yourSecurityToken";
// Set yourEndpoint to the endpoint of the region in which the bucket is located. For example, if your bucket is located in the China (Hangzhou) region, set yourEndpoint to https://oss-cn-hangzhou.aliyuncs.com. 
$endpoint = "yourEndpoint";
// Specify the bucket name. 
$bucket= "examplebucket";
// Specify the full path of the object. The full path does not contain the bucket name. 
$object = "exampleobject.txt";
// Specify the string that you want to upload. 
$content = "Hello OSS";

try {
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false, $securityToken);
    // Upload the string to the object by using the temporary access credential that is obtained from STS. 
    $ossClient->putObject($bucket, $object, $content);
} catch (OssException $e) {
    print $e->getMessage();
}            
# -*- coding: utf-8 -*-
        from aliyunsdkcore.request import CommonRequest
        from aliyunsdkcore import client
        import json
        import oss2

        # Specify the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com. 
        endpoint = 'https://oss-cn-hangzhou.aliyuncs.com'
        # Security risks may arise if you use the AccessKey pair of an Alibaba Cloud account to access OSS because the account has permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine O&M. To create a RAM user, log on to the RAM console. 
        access_key_id = 'yourAccessKeyId'
        access_key_secret = 'yourAccessKeySecret'
        # Specify the name of the bucket. Example: examplebucket. 
        bucket_name = 'examplebucket'
        # Specify the full path of the object. The full path cannot contain the bucket name. Example: exampledir/exampleobject.txt. 
        object_name = 'exampledir/exampleobject.txt'
        # To obtain the Alibaba Cloud Resource Name (ARN) information of the RAM role, log on to the RAM console. In the left-side navigation pane, choose Identities > Roles. On the Roles page, search for and click the created RAM role. In the Basic Information section of the role details page, you can view and copy the ARN information. 
        # Specify the ARN information of the RAM role. Format: acs:ram::$accountID:role/$roleName. 
        # Specify $accountID as your Alibaba Cloud account. To view the Alibaba Cloud account ID, perform the following steps: Log on to the OSS console, and move the pointer over the profile picture in the upper-right corner or click Basic Information. 
        # Specify $roleName as the name of the RAM role. To view the RAM role name, perform the following steps: Log on to the RAM console. In the left-side navigation pane, click RAM Roles. In the RAM Role Name column on the page that appears, view the name of the RAM role. 
        role_arn = 'acs:ram::17464958********:role/ossststest'

        # Create a RAM policy. 
        # The policy specifies that PutObject operations can be performed only on objects in the bucket named examplebucket. 
        policy_text = '{"Version": "1", "Statement": [{"Action": ["oss:PutObject"], "Effect": "Allow", "Resource": ["acs:oss:*:*:examplebucket/*"]}]}'

        clt = client.AcsClient(access_key_id, access_key_secret, 'cn-hangzhou')

        request = CommonRequest(product="Sts", version='2015-04-01', action_name='AssumeRole')
        request.set_method('POST')
        request.set_protocol_type('https')
        request.add_query_param('RoleArn', role_arn)
        request.add_query_param('RoleSessionName', 'SessionTest')
        # If the RAM policy is left empty, the user has all permissions of the RAM role. If you have specific requirements on the permissions, refer to the preceding configuration of policy_text. 
        request.add_query_param('Policy', policy_text)
        request.set_accept_format('JSON')

        body = clt.do_action_with_exception(request)

        # Use the AccessKey pair of the RAM user to apply for a temporary access credential from STS. 
        token = json.loads(oss2.to_unicode(body))

        # Initialize the StsAuth instance with the authentication information in the temporary access credential. 
        auth = oss2.StsAuth(token['Credentials']['AccessKeyId'],
                            token['Credentials']['AccessKeySecret'],
                            token['Credentials']['SecurityToken'])

        # Initialize a bucket with the StsAuth instance. 
        bucket = oss2.Bucket(auth, endpoint, bucket_name)

        # Upload the object. 
        content = 'testabc'
        result = bucket.put_object(object_name, content)
        print('http response status: ', result.status)
                    
package main


import (
    "fmt"
    "github.com/aliyun/aliyun-oss-go-sdk/oss"
    "os"
)

func main() {    
    // Specify the security token obtained from STS. 
    securitytoken := "yourSecurityToken"
    // Specify the temporary AccessKey pair obtained from STS. 
    // You can use the AccessKey pair and security token contained in the temporary access credential obtained from STS to create an OSSClient. 
    // Create an OSSClient instance. 
    client, err := oss.New("yourEndpoint", "yourAccessKeyId", "yourAccessKeySecret", oss.SecurityToken(securitytoken))
    if err != nil {
        fmt.Println("Error:", err)
    os.Exit(-1)    

    }
    // Specify the name of the bucket. Example: examplebucket. 
    bucketName := "examplebucket"
    // Specify the full path of the object. The full path cannot contain the bucket name. Example: exampledir/exampleobject.txt. 
    objectName := "exampledir/exampleobject.txt"
    // Specify the full path of the local file to upload. Example: D:\\localpath\\examplefile.txt. 
    filepath := "D:\\localpath\\examplefile.txt"
    bucket,err := client.Bucket(bucketName)
    // Upload the object by using the temporary access credential that is obtained from STS. 
    err = bucket.PutObjectFromFile(objectName,filepath)
    fmt.Println(err)
}                    

Signed URL

Notice A validity period must be set for an STS temporary access credential and a signed URL. When you use an STS temporary account credential to generate a signed URL that is used to perform operations such as object upload and download, the minimum validity period takes precedence. For example, you can set the validity period of your STS temporary access credential to 1,200 seconds and the validity period of your signed URL generated by using this credential to 3,600 seconds. In this case, the signed URL cannot be used to upload objects after the STS temporary access credential expires, even if the signed URL is within its validity period.

You can generate a signed URL and provide the URL to a visitor for temporary access. When you generate a signed URL, you can specify the validity period of the URL to limit the period of access from visitors. By default, the validity period of a signed URL is 3,600 seconds. The maximum validity period of a signed URL is 32,400 seconds.

You can add signature information to a URL and provide the URL to a third-party user for authorized access. For more information, see Add signatures to URLs.

Use OSS SDK

The following code provides examples on how to use a signed URL to grant a third-party user permissions to directly upload objects to OSS by using OSS SDKs for common programming languages. For more information about how to use OSS SDKs for other programming languages to perform this operation, see Overview.

// Set yourEndpoint to the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set yourEndpoint to https://oss-cn-hangzhou.aliyuncs.com. 
String endpoint = "yourEndpoint";
// Specify the temporary AccessKey pair obtained from STS. 
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// Specify the security token obtained from STS. 
String securityToken = "yourSecurityToken";
// Specify the name of the bucket. Example: examplebucket. 
String bucketName = "examplebucket";
// Specify the full path of the object. Example: exampleobject.txt. The path cannot contain the bucket name. 
String objectName = "exampleobject.txt";

// Create an OSSClient instance. 
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

// Specify the expiration time of the signed URL. 
Date expiration = null;
try {
    expiration = DateUtil.parseRfc822Date("Wed, 18 Mar 2022 14:20:00 GMT");
} catch (ParseException e) {
    e.printStackTrace();
}
// Create a request to generate the signed URL. 
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);
// Specify the expiration time of the request. 
request.setExpiration(expiration);
// Set ContentType. 
request.setContentType("application/txt");
// Add user metadata. 
request.addUserMetadata("author", "aliy");
// Generate a signed URL that allows HTTP PUT requests. 
URL signedUrl = ossClient.generatePresignedUrl(request);
System.out.println("signed url for putObject: " + signedUrl);

// Use the signed URL to send a request. 
// Specify the full path of the local file that you want to upload. By default, if you do not specify the full path of the local file, the local file is uploaded from the path of the project to which the sample program belongs. 
File f = new File("D:\\localpath\\examplefile.txt");
FileInputStream fin = null;
try {
    fin = new FileInputStream(f);
} catch (FileNotFoundException e) {
    e.printStackTrace();
}
// Add headers to the PutObject request. 
Map<String, String> customHeaders = new HashMap<String, String>();
customHeaders.put("Content-Type", "application/txt");
customHeaders.put("x-oss-meta-author", "aliy");

PutObjectResult result = ossClient.putObject(signedUrl, fin, f.length(), customHeaders);

// Shut down the OSSClient instance. 
ossClient.shutdown();                           
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\OssClient;
use OSS\Core\OssException;
use OSS\Http\RequestCore;
use OSS\Http\ResponseCore;

// Specify the temporary AccessKey ID and AccessKey secret that are obtained from STS. 
$accessKeyId = "yourAccessKeyId";
$accessKeySecret = "yourAccessKeySecret";
// Specify the security token that is obtained from STS. 
$securityToken = "yourSecurityToken";
// Set yourEndpoint to the endpoint of the region in which the bucket is located. For example, if your bucket is located in the China (Hangzhou) region, set yourEndpoint to https://oss-cn-hangzhou.aliyuncs.com. 
$endpoint = "yourEndpoint";
// Specify the bucket name. 
$bucket= "examplebucket";
// Specify the full path of the object. The full path does not contain the bucket name. 
$object = "exampleobject.txt";
// Set the validity period of the URL to 3,600 seconds. 
$timeout = 3600;
try {
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false, $securityToken);

    // Generate a signed URL. 
    $signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "PUT");
} catch (OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}
print(__FUNCTION__ . ": signedUrl: " . $signedUrl . "\n");

// Use the signed URL to upload a string to the object. 
// Specify the string that you want to upload. 
$content = "Hello OSS";
$request = new RequestCore($signedUrl);
// Set the method to access the signed URL to PUT. 
$request->set_method('PUT');
$request->add_header('Content-Type', '');
$request->add_header('Content-Length', strlen($content));
$request->set_body($content);
$request->send_request();
$res = new ResponseCore($request->get_response_header(),
    $request->get_response_body(), $request->get_response_code());
if ($res->isOK()) {
    print(__FUNCTION__ . ": OK" . "\n");
} else {
    print(__FUNCTION__ . ": FAILED" . "\n");
};                 
# -*- coding: utf-8 -*-
import oss2

# Security risks may arise if you use the AccessKey pair of an Alibaba Cloud account to access OSS because the account has permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine operations and management. To create a RAM user, log on to the RAM console. 
auth = oss2.Auth('yourAccessKeyId', 'yourAccessKeySecret')
# Set yourEndpoint to the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set yourEndpoint to https://oss-cn-hangzhou.aliyuncs.com. 
# Specify the name of the bucket. Example: examplebucket. 
bucket = oss2.Bucket(auth, 'yourEndpoint', 'examplebucket')
# Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name. 
object_name = 'exampledir/exampleobject.txt'

# Generate a signed URL that is used to upload the object. The validity period of the URL is 60 seconds. 
# By default, OSS identifies the forward slashes (/) in the full path of an object as escape characters when the signed URL is generated. Therefore, you cannot directly use the signed URL. 
# Set the slash_safe parameter to True. This way, OSS does not identify the forward slashes (/) in the full path of the object as escape characters. Then, you can directly use the generated signed URL. 
url = bucket.sign_url('PUT', object_name, 60, slash_safe=True) 
print('the address of the signed URL:', url)

# Use the signed URL to upload an object. 
# Specify the full path of the local file that you want to upload. Example: D:\\localpath\\examplefile.txt. 
# By default, if you set this parameter to the name of a local file such as examplefile.txt without specifying the local path, the local file is uploaded from the local path of the project to which the sample program belongs. 
result = bucket.put_object_with_url_from_file(url, 'D:\\localpath\\examplefile.txt')
print(result.status)         
package main

import (
    "fmt"
    "os"
    "strings"

    "github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func HandleError(err error) {
    fmt.Println("Error:", err)
    os.Exit(-1)
}

func main() {
    // After you obtain a temporary STS credential, you can use the security token and temporary AccessKey pair (AccessKey ID and AccessKey secret) that are contained in the credential to create an OSSClient. 
    client, err := oss.New("yourEndpoint", "yourAccessKeyId", "yourAccessKeySecret", oss.SecurityToken("yourSecurityToken"))
    if err != nil {
        HandleError(err)
    }
    // Specify the name of the bucket to which the local file is uploaded. Example: examplebucket. 
    bucketName := "examplebucket"
    // Specify the full path of the object to which the uploaded file is stored. Example: exampledir/exampleobject.txt. The full path of the object cannot contain bucket names. 
    objectName := "exampledir/exampleobject.txt"
    // Specify the full path of the local file to upload. Example: D:\\localpath\\examplefile.txt, in which localpath indicates the local path in which the file is stored. 
    localFilename := "D:\\localpath\\examplefile.txt"

    // Obtain the bucket. 
    bucket, err := client.Bucket(bucketName)
    if err != nil {
        HandleError(err)
    }

    // Generate a signed URL to upload the object. 
    signedURL, err := bucket.SignURL(objectName, oss.HTTPPut, 60)
    if err != nil {
        HandleError(err)
    }

    var val = "Go with Alibaba Cloud"
    err = bucket.PutObjectWithURL(signedURL, strings.NewReader(val))
    if err != nil {
        HandleError(err)
    }

    // Generate a signed URL that contains custom parameters to upload the object. Make sure that the value of the ContentType parameter contained in the URL is the same as the content type specified in the browser. 
    options := []oss.Option{
        oss.Meta("myprop", "mypropval"),
        oss.ContentType("text/plain"),
    }

    signedURL, err = bucket.SignURL(objectName, oss.HTTPPut, 60, options...)
    if err != nil {
        HandleError(err)
    }

    err = bucket.PutObjectFromFileWithURL(signedURL, localFilename, options...)
    if err != nil {
        HandleError(err)
    }
}
                    
using Aliyun.OSS;
using Aliyun.OSS.Common;
// Set yourEndpoint to the endpoint of the region in which the bucket is located. For example, if the bucket is located in the China (Hangzhou) region, set yourEndpoint to https://oss-cn-hangzhou.aliyuncs.com. 
var endpoint = "<yourEndpoint>";
// Security risks may arise if you use the AccessKey pair of an Alibaba Cloud account to access OSS because the account has permissions on all API operations. We recommend that you use a RAM user to call API operations or perform routine O&M. To create a RAM user, log on to the RAM console. 
var accessKeyId = "<yourAccessKeyId>";
var accessKeySecret = "<yourAccessKeySecret>";
// Specify the bucket name. 
var bucketName = "<yourBucketName>";
// Specify the object name. The object name is the full path of the object. The path of the object cannot contain the bucket name. Example: exampledir/exampleobject.txt. 
var objectName = "<yourObjectName>";
var objectContent = "More than just cloud.";
// Create an OSSClient instance. 
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    // Generate a signed URL. 
    var generatePresignedUriRequest = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Put)
    {
        // Set the validity period of the signed URL. Default value: 3600. Unit: seconds. 
        Expiration = DateTime.Now.AddHours(1),
    };
    var signedUrl = client.GeneratePresignedUri(generatePresignedUriRequest);
    // Use the signed URL to upload an object. 
    var buffer = Encoding.UTF8.GetBytes(objectContent);
    using (var ms = new MemoryStream(buffer))
    {
        client.PutObject(signedUrl, ms);
    }
    Console.WriteLine("Put object by signatrue succeeded. {0} ", signedUrl.ToString());
}
catch (OssException ex)
{
    Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
        ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}
catch (Exception ex)
{
    Console.WriteLine("Failed with error info: {0}", ex.Message);
}
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;

int main(void)
{
     /* Initialize the OSS account information. */
    std::string AccessKeyId = "yourAccessKeyId";
    std::string AccessKeySecret = "yourAccessKeySecret";
    std::string Endpoint = "yourEndpoint";
    std::string BucketName = "yourBucketName";
    std::string PutobjectUrlName = "yourPutobjectUrlName";

     /* Initialize network resources. */
    InitializeSdk();

    ClientConfiguration conf;
    OssClient client(Endpoint, AccessKeyId, AccessKeySecret, conf);

    /* Set the validity period of the signed URL.*/
    std::time_t t = std::time(nullptr) + 1200;
    /* Generate the signed URL. */
    auto genOutcome = client.GeneratePresignedUrl(BucketName, PutobjectUrlName, t, Http::Put);
    if (genOutcome.isSuccess()) {
        std::cout << "GeneratePresignedUrl success, Gen url:" << genOutcome.result().c_str() << std::endl;
    }
    else {
        /* Handle exceptions. */
        std::cout << "GeneratePresignedUrl fail" <<
        ",code:" << genOutcome.error().Code() <<
        ",message:" << genOutcome.error().Message() <<
        ",requestId:" << genOutcome.error().RequestId() << std::endl;
        ShutdownSdk();
        return -1;
    }

    std::shared_ptr<std::iostream> content = std::make_shared<std::stringstream>();
    *content << "test cpp sdk";

    /* Use the signed URL to upload the object. */
    auto outcome = client.PutObjectByUrl(genOutcome.result(), content);

    if (! outcome.isSuccess()) {
        /* Handle exceptions. */
        std::cout << "PutObjectByUrl fail" <<
        ",code:" << outcome.error().Code() <<
        ",message:" << outcome.error().Message() <<
        ",requestId:" << outcome.error().RequestId() << std::endl;
        ShutdownSdk();
        return -1;
    }

    /* Release network resources. */
    ShutdownSdk();
    return 0;
}