Back

Blog details

Generating Presigned URLs on AIOZ Storage with Python

AIOZ Network
5 min readAugust 09, 2026
aioz-storage
Generating Presigned URLs on AIOZ Storage with Python

A presigned URL lets someone upload or download a specific object on AIOZ Storage without ever holding your credentials, a temporary, scoped link instead of a shared access grant. Generating one against AIOZ Storage takes exactly one boto3 method, generate_presigned_url, plus the same endpoint configuration every other AIOZ Storage Python script needs. This guide covers both directions, download links and upload links, and the one detail that actually matters: how long the link stays valid.

TL;DR:

  • generate_presigned_url('get_object', ...) creates a temporary download link; the same method with 'put_object' creates a temporary upload link.
  • Presigned URLs work against AIOZ Storage exactly like they work against S3, since signing happens client-side and doesn't depend on anything AIOZ-specific beyond the endpoint config.
  • The ExpiresIn parameter controls how long the link works, in seconds, and there is no way to revoke a presigned URL early once it's been handed out.

Do Presigned URLs Work on AIOZ Storage the Same Way They Work on S3?

Yes, without any AIOZ-specific workaround. Presigned URL generation is a client-side signing operation, boto3 computes a cryptographic signature using your credentials and embeds it in the URL, and the receiving server just validates that signature against the request. Since AIOZ Storage speaks the same S3-compatible API, that validation works identically to Amazon S3, provided your boto3 client is configured with AIOZ Storage's endpoint and addressing_style: path, the same setup every other AIOZ Storage Python script in this series uses.

Setting Up the Client

import boto3
from botocore.config import Config

s3_client = boto3.client(
    "s3",
    region_name="us-east-1",
    endpoint_url="https://s3.aiozstorage.network",
    aws_access_key_id="<your-aioz-storage-access-key-id>",
    aws_secret_access_key="<your-aioz-storage-secret-access-key>",
    config=Config(
        request_checksum_calculation="when_required",
        response_checksum_validation="when_required",
        s3={"addressing_style": "path"},
    ),
)

Apart from the two checksum settings, this is the same client configuration AIOZ's own SDK documentation specifies, and it's the only setup step presigned URLs need beyond a valid access grant.

The checksum settings matter only if you also upload through this client. Since 1.36.0, boto3 sends such uploads chunked without the Content-Length header AIOZ Storage needs (see AWS's data integrity settings and the botocore Config reference). Presigned URLs don't carry that default checksum, because botocore skips it for presigned requests, so the URLs below are unaffected. We confirmed the Content-Length requirement on Oct 19, 2026.

Generating a Presigned Download URL

url = s3_client.generate_presigned_url(
    "get_object",
    Params={"Bucket": "your-bucket", "Key": "your-object-key"},
    ExpiresIn=3600,
)
print(url)

That URL works in a browser or any HTTP client for the next hour (3600 seconds), no AIOZ Storage credentials required on the requesting end. Anyone with the link can download that specific object until it expires, and nothing else in the bucket.

Laptop screen displaying colorful lines of source code

Generating a Presigned Upload URL

url = s3_client.generate_presigned_url(
    "put_object",
    Params={"Bucket": "your-bucket", "Key": "new-object-key"},
    ExpiresIn=3600,
)

The difference is the operation name, put_object instead of get_object, and what the URL is good for: a client can PUT a file directly to that URL and it lands in your bucket at the key you specified, without ever touching your application server or holding your AIOZ Storage credentials. This is the pattern behind most "upload directly from the browser" flows, your backend generates the URL, the browser does the actual upload.

The Real Gotcha: Content-Type Must Match Exactly

If you include ContentType when generating an upload URL, the client's actual PUT request has to send that exact same Content-Type header, or the request fails with SignatureDoesNotMatch. That's not an AIOZ Storage quirk, it's how S3-style request signing works generally: any parameter included when the URL was signed becomes part of what the receiving server checks against, and a mismatch anywhere breaks the signature.

url = s3_client.generate_presigned_url(
    "put_object",
    Params={"Bucket": "your-bucket", "Key": "photo.jpg", "ContentType": "image/jpeg"},
    ExpiresIn=900,
)

Whoever uses that URL needs to send Content-Type: image/jpeg on the actual PUT request, not image/jpg, not left blank, not anything else. If you don't need to constrain the content type, leave ContentType out of Params entirely rather than setting it to something generic, since an included-but-wrong value fails, while an omitted value just doesn't get checked.

Laptop displaying a code editor with dark theme and syntax highlighting

How Long Should ExpiresIn Actually Be?

Shorter than feels convenient, as a default. ExpiresIn is in seconds, and there's no method to revoke a presigned URL once it's been generated, waiting it out is the only way it stops working. A download link handed to a user for an immediate action (viewing a file, downloading a report) can reasonably use a short window, 300 to 900 seconds. An upload URL generated for a client-side upload flow that might take a while on a slow connection needs enough headroom to actually finish, but there's an outer limit either way: AWS documents a 7-day (604800 seconds) maximum for presigned URLs generated with long-term credentials (stated directly for the AWS CLI's presign command, and the same SigV4 signing process boto3 uses underneath), a ceiling AIOZ Storage's S3-compatible API inherits since presigned URL expiry is enforced by the signature itself, not a server-side setting. Don't default to the maximum just because it's available, scope the expiry to how long the link actually needs to work.

Frequently Asked Questions

What boto3 method generates a presigned URL for AIOZ Storage?
generate_presigned_url, with 'get_object' for a download link or 'put_object' for an upload link, called on a boto3 S3 client configured with AIOZ Storage's endpoint.

Do presigned URLs require any AIOZ-specific configuration?
No beyond the standard AIOZ Storage boto3 client setup, endpoint_url and addressing_style: path. Signing itself is a client-side operation with no server round trip.

Can I revoke a presigned URL before it expires?
No. There's no API call to invalidate a presigned URL early. If you need that control, use a shorter ExpiresIn value in the first place rather than relying on being able to cancel it later.

What's the maximum expiration time for a presigned URL?
7 days (604800 seconds) with long-term credentials, per AWS's documentation for the underlying SigV4 signing process, a limit AIOZ Storage's S3-compatible API inherits since expiry is enforced through the signature, not a server-side policy.

Can someone use a presigned upload URL to overwrite a different file?
No. The URL is signed for a specific bucket and key combination. It can't be used to write to a different object than the one it was generated for.

Why does my presigned upload URL fail with SignatureDoesNotMatch?
Usually a Content-Type mismatch. If you included ContentType when generating the URL, the client's actual PUT request must send that exact same header value, or the signature check fails.

Is a presigned URL the same thing as an access grant?
No. An access grant is a broader, AIOZ Storage-specific credential covering multiple actions and objects. A presigned URL is scoped to exactly one operation on exactly one object, generated by a client already holding valid credentials.

References

We only send updates when meaningful changes ship, and you can unsubscribe anytime

Related Content

blog thumbnail

How to Create a Bucket and Upload a File on AIOZ Storage

Create a bucket and upload a file on AIOZ Storage in five steps: sign up, set a passphrase, add credits, and upload. Plus what the passphrase cannot recover.

aioz-storage
5 min readOctober 20, 2026
blog thumbnail

AIOZ Storage Rate Limit: Working Within 100 Requests/s

The AIOZ Storage rate limit is 100 requests per second. See what the docs do and don't say, and how to stay under it with boto3 retries and a limiter.

aioz-storage
7 min readOctober 16, 2026
blog thumbnail

What AIOZ Storage Erasure Coding Covers and What It Doesn't

AIOZ Storage erasure coding splits each object into pieces on DePIN nodes, so it survives node loss. See what it covers, what it doesn't, and what to back up.

aioz-storage
6 min readOctober 14, 2026
blog thumbnail

How to Rename a File in an S3 Bucket on AIOZ Storage

Rename a file in an S3 bucket on AIOZ Storage from the dashboard, then move, delete and download files, and see which actions the docs say are not supported.

aioz-storage
5 min readOctober 13, 2026
blog thumbnail

AIOZ Storage llms.txt: Docs Built for Super Intelligence

AIOZ Storage publishes llms.txt, a 46-link docs index, and llms-full.txt, all docs in one 164 KB file. See what each file contains and when to use which.

aioz-storage
6 min readOctober 09, 2026
blog thumbnail

Vector Database vs Agent Memory on AIOZ Storage: A Guide

Vector database vs agent memory on AIOZ Storage: use the vector database for control over embeddings and metadata, Memory for simple Record and Recall calls.

aioz-storage
6 min readOctober 06, 2026