Signed urls for upload
See original GitHub issueFeature request
Is your feature request related to a problem? Please describe.
At Labelflow, we developed a tool to upload images on our Supabase storage, based on one nextJs API route. The goal is for us to abstract the storage method from the client-side by querying a generic upload route to upload any file and to ease the permission management. Indeed, in the server-side function, one service role Supabase client is manipulated to actually make the upload. We use next-auth to secure the route (and to manage authentication in the app in general).
Client-side upload looks like that:
await fetch("https://labelflow.ai/api/upload/[key-in-supabase]", {
method: "PUT",
body: file,
});
Server-side API route looks more or less like that (I don’t show the permission management part):
import { createClient } from "@supabase/supabase-js";
import nextConnect from "next-connect";
const apiRoute = nextConnect({});
const client = createClient(
process?.env?.SUPABASE_API_URL as string,
process?.env?.SUPABASE_API_KEY as string
);
const bucket = "labelflow-images";
apiRoute.put(async (req, res) => {
const key = (req.query.id as string[]).join("/");
const { file } = req;
const { error } = await client.storage.from(bucket).upload(key, file.buffer, {
contentType: file.mimetype,
upsert: false,
cacheControl: "public, max-age=31536000, immutable",
});
if (error) return res .status(404);
return res.status(200);
});
export default apiRoute;
The problem is that we face a serious limitation in terms of upload size since we use Vercel for deployment which doesn’t allow serverless functions to handle requests that are more than 5Mb. Since we send over images in the upload request from the client to the server, we’re likely to reach that limit quite often.
Describe the solution you’d like
As we don’t want to manipulate Supabase clients client-side, we think that the ideal solution would be to allow us to upload directly to Supabase, using an upload signed URL. The above upload route could now take only a key as an input and return a signed URL to make the upload to.
Client-side upload would now be in two steps:
// Get Supabase signed Url
const { signedUrl } = await (await fetch("https://labelflow.ai/api/upload/[key-in-supabase]", {
method: "GET",
})).json();
// Upload the file
await fetch(signedUrl, {
method: "PUT",
body: file,
});
And our API route would look like that, more or less:
import { createClient } from "@supabase/supabase-js";
import nextConnect from "next-connect";
const apiRoute = nextConnect({});
const client = createClient(
process?.env?.SUPABASE_API_URL as string,
process?.env?.SUPABASE_API_KEY as string
);
const bucket = "labelflow-images";
apiRoute.get(async (req, res) => {
const key = (req.query.id as string[]).join("/");
const { signedURL } = await client.storage
.from(bucket)
.createUploadSignedUrl(key, 3600); // <= this is the missing feature
if (signedURL) {
res.setHeader("Content-Type", "application/json");
return res.status(200).json({signedURL});
}
return res.status(404);
});
export default apiRoute;
Describe alternatives you’ve considered
I described them in our related issue:
- Use the Supabase client, client-side. We’d need to give extra care about security, and the fact we don’t use Supabase auth is not helping. Some references to do that: https://supabase.io/docs/guides/auth#row-level-security & https://github.com/supabase/supabase/tree/master/examples/nextjs-ts-user-management#postgres-row-level-security
- Use another storage method (Google Cloud, AWS) that supports upload SignedUrl, in an end-to-end fashion instead of Supabase
- Use another storage method (Google Cloud, AWS) that supports upload SignedUrl as an intermediate. E.g. upload on a GC bucket then download it from the API serverless function and finally upload on Supabase using the client
Additional context
We’re happy to work on developing this feature at Labelflow if you think this is the best option!
Issue Analytics
- State:
- Created 2 years ago
- Reactions:23
- Comments:10 (1 by maintainers)
Hello! Apologies for the late reply,
I really like the idea of a signed URL for upload, I will add this to the backlog for discovery & prioritization
@fenos thanks for that, for me, i don’t need anymore the feature since.
I was able to do APIKEY check with RLS.
If you want to do it too:
First create key_mode, the type of api key:
Then create the table:
Then create the postgress function:
Then add the RLS in table you want to give access:
And in the SDK 1 you can add your APIKEY like that
In SDK v2