Private buckets and signed links
Keep files private, share one file for a limited time with a signed link, and switch a bucket between public and private.
Public buckets are convenient, but anything private, such as receipts, contracts or user uploads, should go in a private bucket. A private bucket never serves files to the public.
Who can read a private file
- Project members signed in to the Console.
- Your project's secret API key (
pgb_sec_...), from your server. - Anyone holding a valid signed link that someone with access created.
Publishable keys (pgb_pub_...) never read private files, because they ship inside apps where anyone can see them. A request without access gets the same "not found" answer as a missing file, so nobody can tell whether a private file exists.
Make a bucket private (or public)
- Open Storage Vault and open the bucket.
- Next to the bucket name you see a Public bucket or Private bucket badge, with a button beside it: Make Private or Make Public.
- Choose it. Making a bucket private asks you to confirm, because its public addresses stop working immediately.
Making a bucket private takes effect within seconds. Copies that a browser or the edge network already fetched are not recalled, so treat a file that was ever public as seen. Making a bucket public exposes every file in it to anyone with the address, so check its contents first. From code, going public needs an explicit confirmation flag (confirmPublic) so it cannot happen by accident. Only members whose role allows managing storage can change visibility.
Share one file with a signed link
In a private bucket, choose Copy Signed Link next to a file. The link works for 15 minutes and is for that one file only. Anyone who has the link can use it until it expires, so send it only to the person who should have it.
Create signed links from your server
With your secret key you can create links in code. With the TypeScript SDK:
// A download link valid for 15 minutes
const { url } = await pgb.storage.createSignedUrl("receipts", "invoices/inv-1.pdf", { expiresIn: 900 });
// An upload link, so a browser can send a file straight to storage
const put = await pgb.storage.createSignedUrl("receipts", "invoices/inv-2.pdf", {
method: "PUT",
contentType: "application/pdf",
});
await pgb.storage.uploadToSignedUrl(put.url, fileBytes, "application/pdf");
You can also create a bucket as private from the start, and change visibility later:
await pgb.storage.createBucket("receipts", { visibility: "private" });
await pgb.storage.setBucketVisibility("assets", "public", { confirmPublic: true });
Limits of signed links
- The default lifetime is 15 minutes. A download link can last at most 24 hours, and an upload link at most 1 hour.
- A link covers one file and one method. A download link also works for a header check, but cannot be used to upload or to open a different file.
- If you pin a
contentTypeon an upload link, the upload must use exactly that type. Without one, uploads of HTML, SVG, XML and JavaScript are refused. - Signed links need the secret key, so create them on a server and give only the finished link to the browser.
Good to know
- The public address of a private file (
/storage/<bucket>/<path>) answers "not found" to anyone without the secret key. - Private and signed responses are sent so that shared caches do not store them.
- Keep the secret key out of client apps. See API keys.