By default, objects in an OSS bucket are private. A presigned URL grants temporary, credential-free access to a specific object. Anyone with the URL can download the object until it expires — no OSS credentials required on the recipient's end.
Use the OSS SDK for Python to generate a presigned URL, then share it with the intended recipient. The recipient can download the object using any HTTP client.
Prerequisites
Before you begin, ensure that you have:
The
oss:GetObjectpermission on the target object (required to allow downloads via the presigned URL)The
OSS_ACCESS_KEY_IDandOSS_ACCESS_KEY_SECRETenvironment variables set with your AccessKey ID and AccessKey secret
Note: Generating a presigned URL itself requires no specific permissions. The oss:GetObject permission is checked when the recipient uses the URL to download.How it works
The object owner generates a presigned URL for a GET request using the OSS SDK for Python.
The owner shares the URL with the recipient.
The recipient sends a GET request to the URL using any HTTP client (curl, browser, or code). No credentials needed.
OSS validates the signature embedded in the URL and returns the object if the URL is still valid.
Generate a presigned URL
All examples in this document use V4 presigned URLs. The URL embeds your signature, the object path, and an expiration time. To generate one, specify:
Object path: The full path of the object, excluding the bucket name (e.g.,
exampledir/exampleobject.txt)HTTP method:
GETfor downloadsExpiration: Validity in seconds, up to 604,800 seconds (7 days)
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# Load credentials from environment variables.
# Set OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET before running this code.
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
# Set the endpoint for the region where your bucket is located.
# Example: China (Hangzhou) public endpoint
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
# The region parameter is required for V4 signatures.
region = "cn-hangzhou"
bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
# Full path of the object, excluding the bucket name.
object_name = 'exampledir/exampleobject.txt'
# Generate a presigned URL valid for 600 seconds.
# slash_safe=True prevents OSS from percent-encoding the forward slashes in the
# object path, which would otherwise make the URL unusable.
url = bucket.sign_url('GET', object_name, 600, slash_safe=True)
print('Presigned URL:', url)The generated URL looks like this:
https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampledir/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******Key parameters in the URL:
| Parameter | Description |
|---|---|
x-oss-date | Timestamp when the signature was created (ISO 8601 format) |
x-oss-expires | Validity duration in seconds, starting from x-oss-date |
x-oss-signature-version | Signing algorithm (OSS4-HMAC-SHA256) |
x-oss-credential | Credential scope: AccessKey ID, date, region, service, and request type |
x-oss-signature | The computed signature that authorizes the request |
Download using the presigned URL
The presigned URL works with any HTTP client. Pass it as a plain GET request — no authentication headers required.
curl
curl -SO "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"Python
import requests
file_url = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"
save_path = "/downloads/exampleobject.txt"
try:
response = requests.get(file_url, stream=True)
if response.status_code == 200:
with open(save_path, 'wb') as f:
for chunk in response.iter_content(4096):
f.write(chunk)
print("Download completed!")
else:
print(f"Download failed. Status code: {response.status_code}")
except Exception as e:
print("Error during download:", e)Java
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class Demo {
public static void main(String[] args) {
String fileURL = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************";
String savePath = "/downloads/myfile.txt";
try {
downloadFile(fileURL, savePath);
System.out.println("Download completed!");
} catch (IOException e) {
System.err.println("Error during download: " + e.getMessage());
}
}
private static void downloadFile(String fileURL, String savePath) throws IOException {
URL url = new URL(fileURL);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
int responseCode = httpConn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = new BufferedInputStream(httpConn.getInputStream());
FileOutputStream outputStream = new FileOutputStream(savePath);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
} else {
System.out.println("No file to download. Server replied HTTP code: " + responseCode);
}
httpConn.disconnect();
}
}Node.js
const https = require('https');
const fs = require('fs');
const fileURL = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************";
const savePath = "/downloads/myfile.txt";
https.get(fileURL, (response) => {
if (response.statusCode === 200) {
const fileStream = fs.createWriteStream(savePath);
response.pipe(fileStream);
fileStream.on('finish', () => {
fileStream.close();
console.log("Download completed!");
});
} else {
console.error(`Download failed. Status code: ${response.statusCode}`);
}
}).on('error', (err) => {
console.error("Error during download:", err.message);
});Go
package main
import (
"io"
"net/http"
"os"
)
func main() {
fileURL := "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************"
savePath := "/downloads/myfile.txt"
response, err := http.Get(fileURL)
if err != nil {
panic(err)
}
defer response.Body.Close()
if response.StatusCode == http.StatusOK {
outFile, err := os.Create(savePath)
if err != nil {
panic(err)
}
defer outFile.Close()
_, err = io.Copy(outFile, response.Body)
if err != nil {
panic(err)
}
println("Download completed!")
} else {
println("No file to download. Server replied HTTP code:", response.StatusCode)
}
}JavaScript (browser)
const fileURL = "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************";
const fileName = "exampleobject.txt";
fetch(fileURL)
.then(response => {
if (!response.ok) {
throw new Error(`Server replied HTTP code: ${response.status}`);
}
return response.blob();
})
.then(blob => {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
document.body.appendChild(link);
link.click();
link.remove();
console.log("Download completed!");
})
.catch(error => {
console.error("Error during download:", error);
});Android (Java)
import android.os.AsyncTask;
import android.os.Environment;
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class DownloadTask extends AsyncTask<String, String, String> {
@Override
protected String doInBackground(String... params) {
String fileURL = params[0];
String savePath = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS) + "/myfile.txt";
try {
URL url = new URL(fileURL);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
int responseCode = httpConn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = new BufferedInputStream(httpConn.getInputStream());
FileOutputStream outputStream = new FileOutputStream(savePath);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
return "Download completed!";
} else {
return "No file to download. Server replied HTTP code: " + responseCode;
}
} catch (Exception e) {
return "Error during download: " + e.getMessage();
}
}
}Objective-C
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString *fileURL = @"https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T092756Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************/20241112/cn-hangzhou/oss/aliyun_v4_request&x-oss-signature=ed5a******************************************************";
NSString *savePath = @"/Users/your_username/Desktop/myfile.txt";
NSURL *url = [NSURL URLWithString:fileURL];
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"Error during download: %@", error.localizedDescription);
return;
}
if (!data) {
NSLog(@"No data received.");
return;
}
NSError *writeError = nil;
BOOL success = [data writeToURL:[NSURL fileURLWithPath:savePath]
options:NSDataWritingAtomic
error:&writeError];
if (success) {
NSLog(@"Download completed!");
} else {
NSLog(@"Error saving file: %@", writeError.localizedDescription);
}
}];
[task resume];
[[NSRunLoop currentRunLoop] run];
}
return 0;
}Other scenarios
Download a specific version of an object
To restrict access to a specific object version, pass the versionId in the headers when generating the presigned URL.
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
region = "cn-hangzhou"
bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
object_name = 'exampledir/exampleobject.txt'
headers = dict()
headers["versionId"] = "CAEQARiBgID8rumR2hYiIGUyOTAyZGY2MzU5MjQ5ZjlhYzQzZjNlYTAyZDE3****"
url = bucket.sign_url('GET', object_name, 600, slash_safe=True, headers=headers)
print('Presigned URL:', url)Use request headers in the presigned URL
If you include request headers (such as Content-Type) when generating the URL, the recipient must send the same headers in the GET request. Otherwise, OSS rejects the request with a signature error.
Step 1: Generate the URL with request headers.
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
region = "cn-hangzhou"
bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
object_name = 'exampledir/exampleobject.txt'
headers = dict()
headers['Content-Type'] = 'text/plain; charset=utf8'
# Optional query parameters (uncomment as needed):
params = dict()
# Bandwidth throttling in bit/s (example: 100 KB/s = 100 * 1024 * 8)
# params['x-oss-traffic-limit'] = str(100 * 1024 * 8)
# Restrict access to a specific IP address or CIDR block
# params['x-oss-ac-source-ip'] = "127.0.0.1"
# params['x-oss-ac-subnet-mask'] = "32"
# Restrict access to a specific VPC
# params['x-oss-ac-vpc-id'] = "vpc-t4nlw426y44rd3iq4xxxx"
# Allow or disallow request forwarding
# params['x-oss-ac-forward-allow'] = "true"
url = bucket.sign_url('GET', object_name, 600, slash_safe=True, headers=headers, params=params)
print('Presigned URL:', url)Step 2: Download using the URL, passing the same headers.
curl:
curl -X GET "https://examplebucket.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241113T093321Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************&x-oss-signature=ed5a******************************************************" \
-H "Content-Type: text/plain; charset=utf8" \
-o "myfile.txt"Python:
import requests
def download_file(signed_url, file_path, headers=None):
"""
Downloads an object using a presigned URL.
:param signed_url: The presigned URL.
:param file_path: Local path to save the downloaded object.
:param headers: HTTP headers that were included when generating the URL.
"""
if not headers:
headers = {}
try:
response = requests.get(signed_url, headers=headers, stream=True)
print(f"Status code: {response.status_code}")
if response.status_code == 200:
with open(file_path, 'wb') as file:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
file.write(chunk)
print("Download completed!")
else:
print("Download failed.")
print(response.text)
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
signed_url = "<signedUrl>"
file_path = "/downloads/exampleobject.txt"
headers = {
"Content-Type": "text/plain; charset=utf-8",
}
download_file(signed_url, file_path, headers=headers)Generate a presigned URL using a custom domain name
To generate the URL using a custom domain name bound to your bucket, set is_cname=True and pass the custom domain as the endpoint.
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
region = "cn-hangzhou"
# Set the custom domain name as the endpoint.
endpoint = 'http://static.example.com'
bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region, is_cname=True)
object_name = 'exampledir/exampleobject.txt'
url = bucket.sign_url('GET', object_name, 600, slash_safe=True)
print('Presigned URL:', url)Usage notes
Examples use the public endpoint for the China (Hangzhou) region (
https://oss-cn-hangzhou.aliyuncs.com). If you access OSS from another Alibaba Cloud service in the same region, use the internal endpoint instead. For a full list of regions and endpoints, see Regions and endpoints.The
regionparameter is required when using V4 signatures. It must match the region of your bucket's endpoint.The maximum validity period for a V4 presigned URL is 7 days (604,800 seconds).
A presigned URL can be used multiple times until it expires. After expiry, generate a new URL.
To create an OSSClient instance using Security Token Service (STS) temporary credentials or a custom domain name, see Initialization (Python SDK V1).
For more information on V4 signatures, see Signature V4 (recommended).
Security considerations
Treat a presigned URL as a bearer token — anyone who has the URL can download the object until it expires. To reduce exposure:
Set the shortest expiration time that meets your use case.
Share URLs only with the intended recipient.
If a URL is compromised before it expires, there is no built-in way to revoke it. Generate a new URL with a different expiration if needed.
For permission setup, see Common examples of RAM policies.