Learning objectives
After reading this article you will be able to:
- Decide which files should be public and which private
- Test with curl that a file is really protected
- Choose between a presigned URL and a share link to open a private file
On this page
- What is the difference between a public and a private file?
- Which files should be public and which private?
- How do I test that a file is really protected?
- How do I give someone access to a private file?
- Does sharing a public file protect it?
- What mistakes should I avoid?
- How to do this on Square Cloud
- FAQs
Every file you put in object storage carries a decision: who can open it. Logos, product images and your site's JavaScript must be visible to everyone. Contracts, invoices and photos of ID documents must not.
The expensive mistake is making public something that should be private. The file leaks without a single error, because serving public files is exactly what the storage was set up to do. So decide the visibility before you upload, and check it afterwards with a simple test.
What is the difference between a public and a private file?#
Public: anyone with the URL downloads the file, with no login, no signature and no expiry. The URL is permanent and can be cached by a CDN, which makes delivery fast and cheap.
Private: a request without authorization gets an error (usually 403). Access needs the owner's credentials or a link the owner generated, with an expiry and, sometimes, a way to cancel it.
Visibility is not a property a file has "by nature". It is a setting on the bucket, the folder or the object, and you can change it. What you cannot change is what already left: a public URL someone copied keeps working for as long as the file stays public.
Which files should be public and which private?#
A simple rule: if the content can appear on an open page with no login, it can be public. If it appears only after authentication, it is private.
| File type | Visibility | Why |
|---|---|---|
| Site images, CSS, JS, fonts | Public | Everyone sees them, CDN caching helps |
| Avatars and product images | Public | Already shown on open pages |
| Invoices, contracts, tax documents | Private | One person's data |
| ID photos, medical exams | Private | Sensitive personal data |
| Exports and reports | Private | Contain internal data |
| Subscriber-only media | Private | Access is part of the product |
When in doubt, start private. Opening a file later is a one-line change; closing it later does not recall what was already copied.
How do I test that a file is really protected?#
Request the direct URL with no credentials, the way a stranger would. Use a terminal or a private browser window:
curl -I "https://my-bucket.s3.amazonaws.com/invoices/2026-10.pdf"A private file answers something like:
HTTP/1.1 403 ForbiddenA public file answers HTTP/1.1 200 OK. If your "private" file returns 200, it is not private, however impossible the URL looks to guess. Repeat the test after any change to policies or permissions.
On Amazon S3 (see what S3-compatible storage is), the official documentation says new buckets, access points and objects don't allow public access by default. Block Public Access has four settings (BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy and RestrictPublicBuckets) that override policies and ACLs, and AWS recommends turning on all four. Other providers have similar controls under different names: look up the equivalent in your provider's documentation.
How do I give someone access to a private file?#
Two mechanisms are common. The choice depends on how long the link needs to last and whether you might need to cancel it early.
Presigned URL (temporary link). Your backend signs a URL with a short expiry. Whoever opens it downloads the file, with no account and no credentials. You cannot cancel one specific link before it expires. Details in what a presigned URL is.
Share link. A longer-lived link, recorded in the storage, that the owner can revoke. It suits a file you distribute for days and may want to pull back.
A Python example with boto3 (pip install boto3), with credentials in environment variables:
import os
import boto3
from botocore.config import Config
s3 = boto3.client(
"s3",
region_name="us-east-1",
endpoint_url=os.environ.get("S3_ENDPOINT"), # omit on AWS S3
aws_access_key_id=os.environ["S3_ACCESS_KEY"],
aws_secret_access_key=os.environ["S3_SECRET_KEY"],
config=Config(signature_version="s3v4"),
)
url = s3.generate_presigned_url(
ClientMethod="get_object",
Params={"Bucket": "my-bucket", "Key": "invoices/2026-10.pdf"},
ExpiresIn=600, # 10 minutes
)
print(url)Run curl -o invoice.pdf "<url>" (with quotes) and the file downloads. The same URL without the signature parameters still returns 403. On Amazon S3 the maximum expiry is 12 hours from the console and 7 days from an SDK or the CLI with IAM user credentials; with temporary credentials, the URL dies when they do.
Does sharing a public file protect it?#
No, and this is the most common mistake. Creating a share link for a file that is already public restricts nothing: the public URL stays open for anyone who has it. Adding a password to the share link does not help either, because the direct path never asks for one.
For a share link (or its password, where the storage offers one) to mean anything, the file has to be private. Only then is the authorized link the sole way in. The right order is to close the file first and only then generate the link.
What mistakes should I avoid?#
- Trusting a long random URL. It leaks through logs, history and forwarded messages. Access control is a check, not a secret in the URL.
- Storing the presigned URL in your database. It expires. Generate a new one on each request from an authenticated user.
- Mixing public and private in the same folder. Separate them by folder or bucket and apply different rules to each. A private file dropped in the public folder is the classic leak.
- Forgetting the cache. A public file may stay cached on a CDN after you close it. After changing visibility, test again and purge the cache if needed.
- Granting more than needed. A link should reach one file, for as long as the task takes.
How to do this on Square Cloud#
On Square Cloud Blob Storage, the decision from the table above becomes the bucket you write to: each account has the fixed buckets public, served by a global CDN at the edge, and private. Logos and product images go in the first; invoices, contracts and exports go in the second. Visibility can also be set per folder, together with expiration, cache, maximum size and allowed extensions, which helps you avoid the classic leak of a private file forgotten in the public folder.
A private file opens three ways, with the differences you just read about: the SigV4 presigned URL your code generates, valid for up to 7 days; the dashboard's temporary link, valid for up to 24 hours and not revocable; and the share link, valid for up to 30 days and revocable, with password and metadata on the Pro and Enterprise plans. Since a link and its password only protect private files, write to private first and create the link afterwards.
The boto3 code above runs against Blob with S3_ENDPOINT=https://s3-blob.squarecloud.app, the auto region in place of us-east-1, the private bucket in place of my-bucket and the S3 keys from the "S3 access" tab of the dashboard, derived from an API key. After your first upload, repeat this article's test: with the signature the file downloads, without it the file must not open. There are no egress or ingress fees, and the included quota ranges from 5 GB to 250 GB depending on the plan. Explore Blob Storage and compare quotas on Pricing.
Blob Storage
S3-compatible object storage with no egress fees
FAQs
Does sharing a public file protect it?
No. A share link is just one more way in. The file's public URL keeps working for anyone who has it. To control access, the file has to be private.
Is a hard-to-guess URL enough to protect a file?
No. Security through obscurity fails as soon as the URL leaks into a log, a browser history or a forwarded message. Anyone with the URL of a public file gets it, with no check at all.
How do I know if a file is public?
Request the direct URL with no credentials, for example with curl -I. A 200 means anyone can open it. A private file answers 403 (or 401, depending on the storage).
Are new S3 buckets private by default?
Yes. According to the AWS documentation, new buckets, access points and objects don't allow public access by default, and Block Public Access stops policies or ACLs from opening them by mistake.
More in Storage
See all 15 articles- What is a presigned (signed) URL?A presigned URL is a temporary link to a private file that works without login or credentials. See how it works, its limits and when to use it.
- What is object storage?Object storage keeps files as objects with a key and metadata, accessed over an HTTP API. See how it works, what it is for and where its limits are.
- 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.