Image Upload from user-facing webpage to DatoCMS, without revealing API key (edited title)

Yes, it is! Sorry, this isn’t a request we run into very often (since many of our customers don’t have their own customers uploading to their CMS). What I proposed is just one method of handling this… it’s not something we have a standard drop-in solution for, I’m afraid.

If you expose your env vars to the browser using NEXT_PUBLIC_, then anybody who can view that webpage can also see your env vars. That isn’t just your users (the humans), but also their browsers (the software)… including any malware they may have in their browser extensions, or on their computers, etc. Even if you trust your users, do you trust them to have up-to-date and secure machines?

It isn’t a very good practice and I would avoid that unless you absolutely have to, since it just takes one API key leak to really wreak havoc on your project.

However, if you don’t use the NEXT_PUBLIC_ prefix, then only your route handler script should be able to access the env var. The script, running on your host (let’s say Vercel), just reads it off its own environment, processes your input, and then returns some output. It will not send the env var to your users’ browsers (unless you specifically tell it to, but you really shouldn’t do that).

EDIT: Made a demo instead.

You can use fetch() to directly send the file to AWS with the presigned URL from the browser, like this:

            const file = fileInput.current.files[0] // fileInput is a useRef() on the file input
            const response = await fetch(s3url,
                {
                    body: file,
                    method: 'PUT',
                    headers: {
                        "Content-Type": file.type
                    },
                }
            )

Full example: s3-presigned-file-upload-demo/src/app/page.tsx at main · arcataroger/s3-presigned-file-upload-demo · GitHub

Demo here: https://s3-presigned-file-upload-demo.vercel.app/


I know this is a lot of work just to upload a file :frowning: I’ll check with the devs too to see if they have any better ideas…