Access Fly secrets in REACT runtime

I have a ReactJS app where I want to store/use some sensitive data. Usually with .env file. But I can not use that file at all. If I want to deploy with GitHub Actions this .env file should be removed from .gitignore, which is surely not what I want. I tried to create that file manually with flyctl ssh sftp shell in app folder or any other, but this .env file disappeared after fly restart or deploy. The other way to have those variables is fly secrets, but I do not understand how to access those secrets from react components. In the case of Rails app fly secrets are accessible as expected, but not for React. Currently I am stuck and need some help from community.

Hi there! When you set secrets in fly, they are available to your app as environment variables. That means a .env file that has a single line with EXAMPLE_SECRET=abc123 is identical to flyctl secrets set EXAMPLE_SECRET=abc123 and both can be accessed with process.env.EXAMPLE_SECRET in a node environment. I hope this helps clarify things. TL;DR: Fly secrets appear the same to your app as secrets set in .env.

It is quite understandable what U said. But in practice app doesn’t see those fly secrets with process.env.REACT_APP_SOME_VAR. That’s why I am trying to hack it with .env file. But this file is vanishing after fly restart.

That very much should work. I encourage you to try exploring with:

fly ssh console -C node

Afa JS runtimes are concerned, in our app, Fly secrets are indeed accessible with process.env or Deno.env.

Can you fly ssh console -s -a <app-name> into an instance and see if printenv <K> | cut -c -8 outputs (first 8 chars of) <V> that you set with fly secrets set -a <app-name> <K>=<V>?

Also, check with fly secrets list -a <app-name> that should show digests of set secrets.

exec: “node”: executable file not found in $PATH

printenv | cut -c -8 prints only ‘https://’ so this do not equals to fly secrets set <K>=<V>.
I have configured secrets with commands like fly secrets set REACT_APP_SOME_KEY=https://somewebsite.com -a <app>. So without any brackets or so.
fly secrets list correctly show all my secrets digests. So as I undestood problem is that my vars are not correctly set

The cut -c -8 was only because I thought the secret is sensitive and hence you may not want it part of the output. Simply doing a printenv <K> should tell you if it equals <V>. And this <V> should be accessible with process.env.<K>. Check the output of fly ssh console -a <app-name> -C 'node -p console.log(process.env.<K>)'

exec: “node”: executable file not found in $PATH

so nodeJS is not installed?

Looks like node isn’t in the logged-in shell’s $PATH (weird).

Any how, as before fly ssh console -a <app-name> and exec printenv <K>. This should match what you set. And this <K> should indeed be accessible with process.env.<K> from within node unless something is mucking with it at runtime.

If you can find a way to exec node -p process.env.<K> when ssh’d into the app’s VM, then that would reveal what env.<K> a node process in the app’s VM is actually seeing.

May be related:

Yes, weird. So lets try the full path:

Try:

fly ssh console -C /root/.volta/bin/node

The default behaviour of React (and most React Frameworks like NextJS) is to build Environment Variables into the application at build time: unless you’re using server-side rendering, Environment Variables will not be available to your React application because all of the code is executed within the browser – which does not have access to your server. The only responsibility of your server is to send your javascript to clients, meaning it’s impossible to have secrets exposed to React that your users cannot see. React’s runtime is your user’s browser.

For example, if your environment has a MY_SECRET Environment Variable with a value of s3cr3t and your source code contains process.env.MY_SECRET, then the build process will perform a string replacement of process.env.MY_SECRET so that your source code now contains value of the MY_SECRET Environment Variable (s3cr3t) which anyone accessing visiting your website will be able to see.

If you’d like to have secrets available to your react application that is not exposed to the client, then you’ll need to use server-side rendering (either implement it yourself or use a framework like Remix). If you have Environment Variables that aren’t secret, but you don’t want to build them into your application (i.e: follow the 12factor methodology), you could perform variable value replacement on startup. You can see my project sparse as an example of achieving that.

(If you’re coming from backend development, Environment Variables are a very common gotcha in React (and other frontend frameworks) because it’s a very different paradigm. Even React frameworks like NextJS (which is both client side and server side) don’t treat Environment Variables as runtime values.)

2 Likes

root directory does not have .volta folder

Can you share your Dockerfile?

I do not have a Docker file. I just used fly launch to deploy my app to Fly.io. Do I have to make some actions related also with Docker?