Learning objectives
After reading this article you will be able to:
- Understand how a presigned URL grants access without a login
- Generate a download and an upload presigned URL in Python
- Know when to use a presigned URL and when to use a revocable link
On this page
Say you keep invoices, contracts or user photos in private storage. Outsiders must not open them, but now and then a user needs to download their own. You don't want to create a storage account for that user or route the file through your server.
A presigned URL solves this: it hands out a link that works for a short time and only for that one file. You will also see it called a signed URL or a pre-signed URL. Amazon S3 and Google Cloud Storage both offer them, and Azure Blob Storage has an equivalent called a shared access signature (SAS).
How does a presigned URL work?#
A presigned URL is an ordinary URL with extra query string parameters. They name the file, the HTTP method (GET to download, PUT to upload) and the moment the link expires. The last parameter is the signature: a hash computed with a secret key that only the storage owner knows.
When someone opens the link, the storage repeats the calculation with the same data. If the signature matches and the link hasn't expired, it serves the file. If someone changes the file name or stretches the expiry in the URL, the signature no longer matches and the request is rejected.
Two details matter in practice:
- The URL carries the authority of whoever signed it. On Amazon S3 the URL uses the credentials of the user who generated it. The person who receives the link needs no credentials or permissions.
- Signing doesn't call the storage. Your backend signs locally, with no network request. Only the person opening the link talks to the storage.
What is a presigned URL used for?#
- Downloading a private file: an authenticated user clicks "download invoice" and gets a link that works for a few minutes.
- Uploading straight from the browser: the app generates a PUT URL and the browser sends the file to storage. The file never touches your server, which saves bandwidth and memory.
- Sending a file to a third party: a partner needs a report once, with no account and no password.
- Protected media: images or videos that only paying users can see.
How do you generate a presigned URL in Python?#
The example uses boto3, the AWS SDK for Python, which also works with S3-compatible storage. Install it with pip install boto3 requests. Credentials come from environment variables, never from the code.
import os
import boto3
import requests
from botocore.config import Config
s3 = boto3.client(
"s3",
region_name=os.environ.get("S3_REGION", "us-east-1"),
endpoint_url=os.environ.get("S3_ENDPOINT"), # omit for AWS S3; set for other S3-compatible storage
aws_access_key_id=os.environ["S3_ACCESS_KEY"],
aws_secret_access_key=os.environ["S3_SECRET_KEY"],
config=Config(signature_version="s3v4"),
)
download_url = s3.generate_presigned_url( # download, valid for 10 minutes
ClientMethod="get_object",
Params={"Bucket": "my-bucket", "Key": "invoices/2026-10.pdf"},
ExpiresIn=600,
)
upload_url = s3.generate_presigned_url( # upload, valid for 5 minutes
ClientMethod="put_object",
Params={"Bucket": "my-bucket", "Key": "uploads/photo.jpg"},
ExpiresIn=300,
)
print(requests.get(download_url).status_code) # 200
with open("photo.jpg", "rb") as f:
print(requests.put(upload_url, data=f).status_code) # 200If you omit ExpiresIn, boto3 uses 3600 seconds (1 hour). The HTTP method of the request must match the one the URL was generated for: a GET URL does not work for PUT.
To test without Python, copy the download_url and run curl -o invoice.pdf "<url>". The quotes are required because the URL contains several & characters.
How long does a presigned URL last, and can you revoke it?#
You choose the lifetime, within the storage's limit. For Amazon S3, the official documentation gives these numbers: up to 12 hours when the link is created in the console, and up to 7 days with the SDK or CLI using IAM user credentials. With temporary credentials, such as an assumed role, the URL expires along with them even if you asked for more time. The 7 days apply to SigV4 signing; other storages have their own ceilings (Google Cloud Storage also allows at most 7 days).
Revocation is the weak spot. The URL isn't recorded anywhere: it is valid because of its signature, and there is no button to cancel one specific link. The real options are deactivating or deleting the credential used to sign (which invalidates every URL signed with it), deleting or moving the file, or using a revocable link mechanism instead of a presigned URL.
That's why the practical rule is to generate short-lived URLs at the moment the user asks and never store the finished URL in your database.
What security precautions should you take?#
- Treat the URL like a password. Whoever has it can access the file. Keep it out of logs, analytics and public messages.
- Use short expiries. Minutes for an on-screen download, a bit longer for uploading large files.
- Limit the signer's permissions. A URL can only do what the signing credential can do. Use a credential restricted to the bucket you need.
- Validate uploads afterwards. A PUT URL accepts whatever is sent. Check file size and type in your backend after the upload, or use a presigned POST (
generate_presigned_post), which accepts size and content-type conditions. - Keep your clock in sync. A drifting clock can invalidate the signature and cause errors such as
SignatureDoesNotMatchon S3. Sync the server with NTP.
Presigned URL or share link: which one to use?#
| Presigned URL | Share link | |
|---|---|---|
| Validity | Short, set at creation | Longer |
| Revocable | No | Yes |
| Who creates it | Your code, on demand | You, once, per file |
| Best for | One-off download or upload, per user | A file you share and may want to cancel |
If the link is used within seconds or minutes, a presigned URL is the right choice. If you hand the link to several people for days and may need to cancel it, use a revocable mechanism. To decide what stays public and what stays private, read public vs private files. To see where boto3 fits in, read what S3 and S3-compatible storage are, and for big files, multipart and resumable uploads.
How to do this on Square Cloud#
On Square Cloud Blob Storage, the opening scenario (invoices and contracts only their owner downloads) lives in the private bucket, and this article's Python code runs against it with three changes: the https://s3-blob.squarecloud.app endpoint, the auto region and the S3 keys you derive from an API key in the "S3 access" tab of the dashboard. SigV4 presigned URLs last up to 7 days and work for downloads (GET) and for direct uploads from the browser (PUT): CORS accepts PUT from any origin, as long as the API key has write permission.
When the link comes from the dashboard instead of your code, the choice is the one in the table above. The temporary link lasts up to 24 hours and cannot be revoked. The share link lasts up to 30 days and can be revoked at any time; password and metadata on the link are available on the Pro and Enterprise plans.
Blob charges no egress or ingress fee, and the included quota ranges from 5 GB to 250 GB depending on the plan. To try it, create the S3 keys in the dashboard, set S3_ENDPOINT and S3_REGION=auto, and run the example against the private bucket. Explore Blob Storage and check each plan's quota on Pricing.
Blob Storage
S3-compatible object storage with no egress fees
FAQs
How long does a presigned URL last?
It depends on the storage and on how the URL was signed. On Amazon S3, the maximum is 7 days with the SDK or CLI using IAM user credentials, and 12 hours from the console. With temporary credentials, the URL expires along with them.
Can you cancel a presigned URL before it expires?
Generally no. The URL stays valid while its signature and the credentials that created it are valid. If you need to revoke access, use a revocable share link or a very short expiry.
Can anyone with the URL download the file?
Yes. A presigned URL works like a bearer token: whoever holds it can access the file until it expires. Treat it like a temporary password and keep it out of public places.
Can a presigned URL be used for uploads?
Yes. You generate a URL for the PUT method, and the browser or the user's app sends the file straight to storage without going through your server.
More in Storage
See all 15 articles- What does 'S3-compatible' storage mean?S3 is Amazon's object storage and its API became the industry standard. Learn what S3-compatible means, what differs between providers, and how to connect.
- Uploading large files: multipart and resumable uploadsMultipart upload splits a large file into parts that are sent in parallel and retried on their own. See the Python walkthrough, how to resume, and common mistakes.
- Object lifecycle rules: expiring and cleaning up files automaticallyA lifecycle rule deletes files automatically after a set age. Learn how to create folder-level expiration rules on S3 with boto3 and how to verify they work.
- Public vs private files: buckets, temporary links and share linksA public file opens for anyone with the URL; a private one only through an authorized link. Learn how to choose, test access and share safely.