Search code examples
securitypasswordsgatsby

How to store and access API keys and passwords with Gatsby?


I am working on a Gatsby app that implements some 3rd party APIs, all requiring personal credentials. Later on I'm planning to also add a DB, so that will require credentials as well. Since all my code is committed to GitHub, I'm looking for a way to store and access these in a secure way.

While I haven't deployed my app yet, the solution should apply to both local development as well as production.

I'd like to mention that I've never (had the chance to) worked with similar problems in that past, thus I don't even know where to look or what I'm supposed to look for to solve this.


Solution

  • It's important to distinguish between two types of secrets in Gatsby: build-time and runtime.

    • Build-time secrets are used in the Gatsby build process, for example when sourcing data from a CMS (you need to use secrets to pull data from your CMS).
    • Runtime secrets are used client-side when you fetch data from an API dynamically, for example when rendering a Mapbox map (you need to pass your API secret to Mapbox on the client).

    Build-time secrets

    You can store build-time secrets as environment variables (Gatsby docs).

    In a nutshell, you'll create a .env.development file with your dev environment variables, and a .env.production file for your prod environment.

    Then, at the beginning of your gatsby-config.js, you'll add this: (no need to install dotenv, it's already a Gatsby dependency)

    require("dotenv").config({
      path: `.env.${process.env.NODE_ENV}`,
    })
    

    Also make sure that your .env files are in your .gitignore to avoid committing them to source control:

    # ignore env variables files
    .env*
    

    As a last step, you'll need to manually add the variables to every service you're using that needs to build your site. Typically this is going to be your host (Netlify for example), and your CI (GitHub Actions for example).

    Runtime secrets

    The strength of Gatsby is fetching data at build time and generating static content. If you can pull your content at build time using a Gatsby source plugin, you should favor this over fetching content at runtime. (See the Gatsby docs on Build-time vs Runtime Data Fetching for more details.)

    However, in some cases, you can't fetch data at build time, for example when fetching dynamic content or rendering a Mapbox map.

    In this case, saving your secrets as environment variables won't be enough, because the secrets will still be exposed in network calls.

    You have several alternative options, for example:

    • Proxy the API calls through a backend-for-frontend, like an Express.js server, and add the secrets to your Express server
    • Use serverless functions to proxy the call without having to host a server, for example with Netlify or AWS Lambda

    Runtime secrets in Gatsby are obviously more complex to deal with than build-time secrets. If your application relies heavily on runtime data fetching, you could also think about replacing Gatsby with Next.js, which nicely supports runtime secrets through API routes (essentially serverless functions bundled in the framework).


    Thanks to HaberdashPI and JakobAttk for their feedback that improved this answer!