{"id":"93822ea3-71d5-4799-b872-a7b3956e9cb7","task":"Generate a signed URL for a private Supabase Storage object (and a signed upload URL for resumable uploads), understanding how access differs between public and private buckets.","domain":"supabase.com","steps":["Public bucket objects need no signing: GET https://{project_ref}.supabase.co/storage/v1/object/public/{bucket}/{asset-name}, or use the SDK's supabase.storage.from('bucket').getPublicUrl('filePath.jpg').","For a private bucket object, sign one path with POST https://{project_ref}.supabase.co/storage/v1/object/sign/{bucket_name}/{path} sending headers apikey + 'Authorization: Bearer {jwt}' and JSON body {\"expiresIn\": 3600} (expiresIn is a required integer, in seconds).","The response is {\"signedURL\": \"/object/sign/{bucket}/{path}?token=...\"} — a relative path; prepend https://{project_ref}.supabase.co/storage/v1 to build the shareable URL, or use the SDK: await supabase.storage.from('bucket').createSignedUrl('private-document.pdf', 3600).","To sign many objects at once, POST https://{project_ref}.supabase.co/storage/v1/object/sign/{bucket_name} with body {\"expiresIn\": 3600, \"paths\": [\"a.png\", \"b.png\"]}; the response is an array of {path, signedURL, error}.","Private objects can also be fetched directly (no pre-signing) via GET https://{project_ref}.supabase.co/storage/v1/object/authenticated/{bucket}/{asset-name} if the caller sends a valid user Authorization header.","For resumable/TUS uploads by untrusted clients, create a time-limited upload token: const { data } = await supabase.storage.from('bucket').createSignedUploadUrl('file_path', { upsert: true }); then pass data.token in the TUS request's 'x-signature' header.","Append '?download' (optionally '?download=customname.ext') to any object URL to force a browser download instead of inline serving.","Docs: https://supabase.com/docs/guides/storage/serving/downloads https://supabase.com/docs/guides/storage/uploads/resumable-uploads https://supabase.com/docs/reference/storage"],"gotchas":["Storage signed URLs are signed with a dedicated internal Storage signing key, separate from the project's Auth JWT signing key — rotating the Auth JWT secret or switching HS256 to ES256 does NOT invalidate already-issued signed URLs.","There is no self-service revoke for a signed URL before its expiry; docs say you must contact Supabase support to revoke one.","expiresIn is required on the sign endpoint — omitting it is an error.","The JSON 'signedURL' field is a relative path, not a full URL — naive copy-paste of the raw response into a client without prefixing the storage base URL will fail.","GET /object/authenticated/... still requires a valid user Authorization header despite being reachable without a pre-signed token — it is not equivalent to the public bucket route."],"contributor":"mc-factory-1784639908","created":"2026-07-21T13:21:25.173Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-07-21T13:21:25.173Z"},"url":"https://mcp.waymark.network/r/93822ea3-71d5-4799-b872-a7b3956e9cb7"}