Download an object by using a signed URL (Swift SDK)
OSS objects are private by default — only the object owner can access them. To grant temporary download access without exposing credentials, generate a signed URL for a GET request using the OSS Swift SDK. The URL embeds an expiration time and can be reused until it expires. After it expires, generate a new one.
How it works
The object owner calls
client.presign()withGetObjectRequestto generate a signed URL.Share the signed URL with the intended recipient.
The recipient makes a GET request to that URL — using curl, an HTTP client, or any language's HTTP library — to download the object.
After the URL expires, generate a new one.
Prerequisites
Before you begin, make sure that you have:
An OSS bucket with the object you want to share
The
oss:GetObjectpermission on that object (required to allow others to download via the signed URL — generating the URL itself requires no specific permissions)The
OSS_ACCESS_KEY_IDandOSS_ACCESS_KEY_SECRETenvironment variables set with your AccessKey ID and AccessKey secret
For more information about permissions, see Common examples of RAM policies.
Usage notes
The code examples use the China (Hangzhou) region (
cn-hangzhou) with a public endpoint. To access OSS from another Alibaba Cloud service in the same region, use an internal endpoint instead. For endpoint mappings by region, see Regions and endpoints.Treat signed URLs as bearer tokens: anyone with the URL can download the object until it expires. Use short expiration times for sensitive content and share URLs only with intended recipients.
Step 1: Generate a signed URL (Swift SDK)
Call client.presign() to generate a signed URL for a GET request. The result contains the URL and any required signed headers.
import AlibabaCloudOSS
import Foundation
@main
struct Main {
static func main() async {
do {
// Specify the region where the bucket is located. Example: China (Hangzhou) is cn-hangzhou.
let region = "cn-hangzhou"
// Optional. Specify the domain name used to access OSS. For the China (Hangzhou) region, set the endpoint to https://oss-cn-hangzhou.aliyuncs.com.
let endpoint: String? = nil
// Specify the bucket name.
let bucket = "yourBucketName"
// Specify the name of the object to download.
let key = "yourObjectName"
// Obtain access credentials from environment variables. Before running the sample code, make sure the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set.
let credentialsProvider = EnvironmentCredentialsProvider()
// Configure the OSS client.
let config = Configuration.default()
.withRegion(region)
.withCredentialsProvider(credentialsProvider)
// Set the endpoint.
if let endpoint = endpoint {
config.withEndpoint(endpoint)
}
// Create an OSS client instance.
let client = Client(config)
// Generate the presigned URL.
let result = try await client.presign(
GetObjectRequest(
bucket: bucket,
key: key
)
)
// Print the result.
print("result:\n\(result)")
} catch {
print("error: \(error)")
}
}
}Replace the following placeholders with your actual values:
| Placeholder | Description | Example |
|---|---|---|
yourBucketName | Name of the bucket containing the object | my-bucket |
yourObjectName | Full path of the object to download | docs/report.pdf |
The generated signed URL follows this structure:
https://<bucket>.oss-<region>.aliyuncs.com/<object>?x-oss-date=<timestamp>&x-oss-expires=<seconds>&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=<credential>&x-oss-signature=<signature>| Parameter | Description |
|---|---|
x-oss-date | The date and time when the signature was created (ISO 8601 format, UTC) |
x-oss-expires | How long the URL remains valid, in seconds, starting from x-oss-date |
x-oss-signature-version | The signing algorithm used to generate the URL |
x-oss-credential | The AccessKey ID and scope information used to calculate the signature |
x-oss-signature | The signature that verifies the URL was signed with the correct secret key |
Step 2: Download the object using the signed URL
Pass the signed URL to any HTTP client to download the object. All examples below use the same URL structure — replace the example URL with the one generated in Step 1.
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******************************************************"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) {
// Specify the presigned URL that allows HTTP GET requests.
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******************************************************";
// Specify the local path to save the downloaded object.
String savePath = "C:/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 = "C:/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. Server responded with code: ${response.statusCode}`);
}
}).on('error', (err) => {
console.error("Error during download:", err.message);
});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 = "C:/downloads/myfile.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"No file to download. Server replied HTTP code: {response.status_code}")
except Exception as e:
print("Error during download:", e)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 := "C:/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
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 = "C:/downloads/myfile.txt"; // Specify the name of the downloaded object.
fetch(fileURL)
.then(response => {
if (!response.ok) {
throw new Error(`Server replied HTTP code: ${response.status}`);
}
return response.blob(); // Convert the response to a blob.
})
.then(blob => {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = savePath;
document.body.appendChild(link); // Ensure the link exists in the document.
link.click(); // Trigger the download.
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 {
// Specify the presigned URL and the local path to save the object.
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"; // Replace your_username with your username.
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];
// Keep the main thread running to complete the asynchronous request.
[[NSRunLoop currentRunLoop] run];
}
return 0;
}Troubleshooting
The URL expires before the configured expiration time.
A signed URL is valid only while the underlying credentials are valid. If the AccessKey credentials or Security Token Service (STS) token used to generate the URL expire before the configured URL expiration, the URL stops working at the credential expiration time. To avoid this, use long-lived AccessKey credentials to generate presigned URLs, or regenerate the URL before the credentials expire.
403 Forbidden error when accessing the URL.
The caller's account lacks the oss:GetObject permission on the target object. Verify that the RAM policy attached to the AccessKey used for generation includes oss:GetObject for the target bucket and object path. See Common examples of RAM policies.
SignatureDoesNotMatch error.
Common causes:
The system clock used to generate the URL drifted significantly from UTC. Synchronize your system clock with a Network Time Protocol (NTP) server.
The URL was modified after generation (for example, a query parameter was altered). Use the URL exactly as returned by
client.presign().The signed headers returned in
result.signedHeaderswere not included in the request. Apply all signed headers to the HTTP request before sending it, as shown in the background download example above.