DEV Community

Cover image for Using Environmental Variables In Firebase Hosting
Scott Bergler
Scott Bergler

Posted on

Using Environmental Variables In Firebase Hosting

Photo Credit: Mariko Margetson

This article is not really a tutorial or even the answer to a question. In a way it is a question itself.

Here I explain the problem I was having and how I solved it up to this point, but I'm almost 100% certain that I'm missing some details and understanding.

My hope is that the article might start some arguments, dialogues and conversations and maybe I'll get more context and information about better ways of solving the problem.

Assumption:

I'm assuming you are generally familiar with Firebase, Firebase Emulators, and Firebase Functions. If not, let me know and I'll see if I can help. I need to write an article about that whole journey anyway.

Context:

An app I'm working on had some API keys hard-coded in it. I wanted to hide this information, but the application needs some of these keys on start up.

Problem:

This Flutter app is deployed with Firebase Hosting. The Hosting environment does not have environmental variables. So how do I set and get the environmental variables the app needs without hard-coding and committing keys and secrets?

I followed (as far as I understood it) the advice given by Frank van Puffelen on Stack Overflow.

I know that there are subtlties in his advice that I'm not getting, especially around his comment "If you want them to remain secret, it's not just about not having them in the code, it's about not using them from the client at all." I still don't understand that statement.

Solution:

In my functions directory I created a .runtimeconfig.json file (and added it to my .gitignore) with the various keys I needed. This is the local development way of setting environmental variables for Firebase Functions.

Then I wrote an HTTPS cloud function called getEnv. This function returns the Functions functions.config() object.

Now I am able to get the keys and secrets I need to start the app by fetching the config object from the getEnv function as the app is starting up.

Final code:

In functions/.runtimeconfig.json:

{
  "algolia": {
    "appid": "ID",
    "apikey": "KEY"
  },
  "webmerge": {
    "key": "KEY",
    "secret": "SECRET",
    "stashkey": "STASH_KEY"
  },
}
Enter fullscreen mode Exit fullscreen mode

In functions/index.ts:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';

. . .

const cors = require('cors')({origin: true});
const envObj = functions.config();

. . .

admin.initializeApp();

export const getEnv = functions.https.onRequest((req, resp) => {
  cors(req, resp, () => resp.status(200).send(JSON.stringify(envObj)));
});

. . .
Enter fullscreen mode Exit fullscreen mode

NOTE: I used the cors package to get around CORS errors when working locally. I would get these errors when localhost:5000 (Emulator hosting) called localhost:5001 (Emulator functions).

In web_flutter/main.dart:

Future<Map<String, dynamic>> fetchEnv(String functionsURL) async {
  var response = await http.get('${functionsURL}/getEnv');
  return json.decode(response.body);
}

Future<void> main() async {
  try {
    var functionsURL = 'FUNCTIONS_URL';
    var app = fb.initializeApp(firebase app details);
    if (window.location.hostname == 'localhost') {
      app.firestore().settings(Settings(
            host: 'localhost:8080',
            ssl: false,
          ));
      functionsURL = 'http://localhost:5001';
    }

    var env = await fetchEnv(functionsURL);

    var searchClient = Algolia.init(
        applicationId: env['algolia']['appid'],
        apiKey: env['algolia']['apikey']);

    runApp(MyApp(
        repository: Repository(app.firestore(), searchClient),
        authentication: Authentication(app.auth())));
  } on fb.FirebaseJsNotLoadedException catch (e) {
    print(e);
  }
}
Enter fullscreen mode Exit fullscreen mode

Once I confirmed that this was working locally, I was able to use firebase functions:config:set to set this data in the live Functions environment and deploy my updated hosting and functions with firebase deploy.

Your Thoughts?

I'd love to hear your thoughts and experience with environmental variables in general and specific to Firebase. Is there a better way to do this?

Thanks for reading!

Top comments (0)