'How does one set private environment variables on Firebase hosting?

With Divshot shutting down recently, I've switched a number of applications over to Firebase hosting. Some of these apps connect to external APIs, so I need a way to store private environment variables (for example, a secret key for S3 access) on Firebase hosting - anyone have any ideas? There's this article - https://www.firebase.com/blog/2015-10-29-managing-development-environments.html - but that's only for non-private environment variables.

Thanks!



Solution 1:[1]

Firebase Hosting can not store private environment variables. It is for static hosting only. If you want to use a private variable, you will need to do that server side.

If you want a "Firebase way" to handle secrets, you can use Firebase Cloud Functions, and set an environment variable in cloud functions. Here is the link to the documentation on how to do so: https://firebase.google.com/docs/functions/config-env

If you don't have cloud functions added to your Firebase hosting you can do so via the Firebase cli tools:

firebase init functions
npm install --save firebase-functions@latest
npm install -g firebase-tools

More about that here: https://firebase.google.com/docs/hosting/functions

In order to set environment variables in cloud functions, you can do so from the command line as well like so:

firebase functions:config:set someservice.key="THE API KEY" someservice.id="THE CLIENT ID"

You can then access the variables from a function like so:

const functions = require('firebase-functions');
const request = require('request-promise');

exports.userCreated = functions.database.ref('/users/{id}').onWrite(event => {
  let email = event.data.child('email').val();

  return request({
    url: 'https://someservice.com/api/some/call',
    headers: {
      'X-Client-ID': functions.config().someservice.id,
      'Authorization': `Bearer ${functions.config().someservice.key}`
    },
    body: {email: email}
  });
});

Solution 2:[2]

You could try out Google's Secret Manager API.

The reasons why this is more secure than storing it as environment variables in Firebase Cloud Functions are:

  1. The Secret Manager API enforces the principle of least privilege. This means that you can restrict access to the secrets and hence only allow authorized users to view/edit the secrets.
  2. The secrets are encrypted using AES-256.
  3. There is an audit logging feature that you can use for anomaly detection.

For more examples of the source codes, you can have a look at the Google Cloud's Secret Manager NPM Package Documentation here.

Hope that it helps!

Solution 3:[3]

I have a solution that works for me, based on this article: https://victorbruce82.medium.com/how-to-deploy-a-react-app-to-different-firebase-hosting-environments-dev-and-prod-da3f4cae9a1e

It uses env-cmd, and you don't need cloud-functions to get the right env variables on the current firebase-hosting the site is running from (Since NODE_ENV always returns production when deployed on firebase)

Based on using two separate firebase projects, one for production, one for development. So after adding a 2nd firebase project, used for development:

Add the dev project to your current one with: firebase use --add, and use alias dev.

Create two .env files: .env.production and .env.development with each a variable like:

APP_ENV="production"

(Change it to development in the .env.development file)

(You can also add API-keys to these .env files, make sure you .gitignore them, so you don't have secrets in your codebase)

Now in you code you can reference this with process.env.APP_ENV:

const websiteConfig = process.env.APP_ENV=== 'production' ? {
  themeColor: '#fff'
} : {
  themeColor: '#ccc'
}

(You can also choose to have a APP_THEME_COLOR in you .env files instead and access it directly, depending on your preference)

Install env-cmd

npm i -D env-cmd

Now add 2 scripts to your package.json:

"build:dev":"env-cmd -f .env.development npm run build && firebase deploy -P dev",
"build:prod":"env-cmd -f .env.production npm run build && firebase deploy -P prod"

Now you can deploy your code to two literaly different environments, but also have them have different environment variables.

(Note: using NODE_ENV in you .env files does not work, it will always return production when deployed on firebase hosting)

Solution 4:[4]

If you're looking to use GitHub actions to deploy to Firebase, you can consider creating .env variables before build and deployment.

Simply set your environment variables as secrets under your GitHub repository settings and in your .github/workflows/{action}.yml, add this step

...
- name: Create env file
    run: |
      touch .env
      echo API_ENDPOINT=${{ secrets.API_ENDPOINT }} >> .env
      echo API_KEY=${{ secrets.API_KEY }} >> .env
      cat .env
...

And in your codebase, just call process.env.API_KEY to use the variable!

Credits goes to @sugarcane and the original answer found here

Solution 5:[5]

In order for React to access these environment variables through process.env, start your environment variable name with REACT_APP_

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 benomatis
Solution 2 erwinleonardy
Solution 3
Solution 4 Fahmiin
Solution 5 David Nguyen