Keeping your keys safe in JAMStack
Tags: javascript, gatsby, jamstack, kenticokontent
Published: 2020-03-20 09:42:13

---
title: Keeping your keys safe in JAMStack
published: true
description: How do you make sure that you don't accidentally upload you API keys to source control? 
tags: javascript, gatsbyjs, jamstack, kenticokontent
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/uywcg0ifgkedp9y6suua.jpg
---

**Working with Kentico Kontent and Gatsby has been a nice learning curve for me, as I pick up and build upon my front-end developer skillset. You can end up taking quite a lot for granted when you're working with .NET. Securing your calls to an API can be one of these things, as you add things like API keys to your `.config` files and make sure that you don't push those files into your git repo.** 

When I started on my journey with [Gatsbyjs][8] and [Kentico Kontent][9], I wasn't clear on a method that I could use to hide my API keys. :confused: As with most things though, a little digging on Google goes a long way and I managed to find two solutions:
1. Using environment variables
2. Create a settings object

Let's look at these in a little more detail.

## Environment Variables

### Creating and using environment variables

Environment variables are settings that are usually stored as key-value pairs that you can use in your application. To store your application settings in environment variables, you can create a `.env` file in your project folder.
The `.env` file format is just a simple flat file, no hierarchy.  As an example,  my `.env` file looks as follows (obviously the values in brackets are replaced):

```
KONTENT_PROJECT_ID=<Kontent Project ID>
KONTENT_PREVIEW_KEY=<Kontent API Key>
KONTENT_PREVIEW_ENABLED=<true of false>
```

Reading that file requires you to have the [`dotenv`][4] module in your project. You can install this using the following:

```
npm install dotenv
```

The using it is as simple as setting it up (in my case at the top of my `gatsby.config` file):

```
require('dotenv').config();
```

As it happens, in my Gatsby project, I have two `.env` files, one for running `gatsby develop` and one for `gatsby build` (one uses the preview mode of Kentico Kontent while the other does not). In order to do this, I pass a little more info to **dotnet** to tell the configuration which file to look for, bypassing in the node environment:

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

This means that when I look at my `gatsby.config` file, I have a much cleaner file that I can commit to my repo that does not contain my various keys as follows:

```
{
  resolve: `@kentico/gatsby-source-kontent`,
  options: {
    deliveryClientConfig: {
      projectId: process.env.KONTENT_PROJECT_ID,
      previewApiKey: process.env.KONTENT_PREVIEW_KEY,
      globalQueryConfig: {
        usePreviewMode: (process.env.KONTENT_PREVIEW_ENABLED == 'true'),
      },
    },
    languageCodenames: [
      `default`
    ]
  }
}
```

What you may notice is that I'm not simply using the value from the `.env` file for the value of `usePreviewMode`. There is a good reason for this and very simple reason for this and that is that `dotenv` does not support boolean values.  If you want to debug out your environment variables you can use the following:
```
console.log(process.env);
```

which means you'll see something like this:

```
{
  KONTENT_PREVIEW_ENABLED: 'true',
  KONTENT_PREVIEW_KEY: 'Swiper, no swiping!',
  KONTENT_PROJECT_ID: 'Swiper, no swiping!',
  NODE_ENV: 'development',
}
```
*(I actually have a load more in there from my Windows environment variables like `PATH`, but we don't need to worry about those here)*
That's it. When you run `npm run build` or `npm run develop` everything should now be picking up your new settings!
![It's working!](https://media.giphy.com/media/dIxkmtCuuBQuM9Ux1E/giphy.gif)

### Ignore the `.env` file!

A key point here is, add your `.env` files to the `.gitignore` file. The whole point here for me is to not commit your keys and other sensitive data to the git repository. 

To achieve this, just add the following to your `.gitignore` file:
```
# dotenv environment variable files
.env*
```
### Using environment variables with Netlify

I'm my scenario, I'm using [Netlify][3] to build and host my solution. If you are too, then you may have already come across the environment variables in your projects build & deploy settings:
![Netlify Environment Variables Screenshot](https://dev-to-uploads.s3.amazonaws.com/i/7odindk7typp9iv0z51q.png)

Netlify has no concept of _build_ or _develop_ environment variables in my setup (hot I think it can support them), so when we run `npm run build`, it simply picks up the available variables and gets on with business.

### Using environment variables with Azure DevOps

At [Ridgeway][5],  we use [Azure DevOps][6] for our build pipelines. Typically, we set up the pipelines using `yaml` files, but the screenshot here uses the _classic_ designer (it's quite an old one):![DevOps  Environment Variables Screenshot](https://dev-to-uploads.s3.amazonaws.com/i/tz6f4cfehnzp9k8nzlyu.png)

If you're editing a `yaml` pipeline, then the option is still there if you click **Variables**  in the top right while editing the pipeline.
![How to edit variables in Azure DevOps](https://dev-to-uploads.s3.amazonaws.com/i/n5e1i69o4cgx9iprlpbw.png)
Then you can just set the values you want. The options here to make things secret are quite a nice touch, as are the tips on how to use them.![Setting up variables in DevOps with yaml](https://dev-to-uploads.s3.amazonaws.com/i/jwvs7cocheq203uoa2pq.png)

## Settings object

### Creating and using a settings object

Another option I've seen in use is the creation of a settings object in a separate file. So for example, on one project we have a file called `gatsby.keys` as follows:

```
module.exports = {
  enablePreviewMode:  false,
  enableSecuredMode:  true,
  securedApiKey:  'Swiper, no swiping!',
  previewApiKey:  'Swiper, no swiping!'
};
```

This is then used in the `gatsby.config` file as follows:

```
const  keys = require('./gatsby-keys');
```
The variables are then used to set up the plugins as before.

This method supports boolean values, so we don't need to do any additional work with those. Again, this file needs to be excluded from the repository using the `.gitignore` file to make sure that we don't push the keys into the wrong place.

### Settings objects in build pipelines

I've only tried this with Azure DevOps, and it required me to add a custom pipeline component to create the key's file. So I have a step in my `yaml` that looks like this:

```
- task: eliostruyf.build-task.custom-build-task.file-creator@5
  displayName: 'Create settings keys'
  inputs:
    fileoverwrite: true
    filepath: 'gatsby-keys.js'
    filecontent: |
      module.exports = {
        enablePreviewMode: true,
        enableSecuredMode: false,
        securedApiKey: 'Swiper, no swiping!',
        previewApiKey: 'Swiper, no swiping!'
      };
```

You can probably spot the flaw in this implementation, right? I'm not using variables so actually, this is a massive fail as those keys are directly in my `yaml` file and so also in source control.

![Fail!](https://media.giphy.com/media/3owypkSIpM8xw6p7W0/giphy.gif)
_(on the upside, it's a private repo)_


## Summary

These are to the two methods that I came across while working on both work and personal projects. The first exposure I had was the settings object. While it solves the issue of booleans, it's note really my favourite. The environment variables appears to be a much more robust approach to things and it's the one I'm going to be using (and asking my team to use) going forward.

If you can find the time, I recommend testing both out and seeing which works best in your case.


_Cover photo by [Chunlea Ju][1] on [Unsplash][2]_

[1]: https://unsplash.com/@chunlea?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
[2]: https://unsplash.com/s/photos/keys?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
[3]: https://netlify.com
[4]: https://github.com/motdotla/dotenv
[5]: https://www.ridgeway.com
[6]: https://azure.microsoft.com/en-us/services/devops
[7]: https://jamstack.org/
[8]: https://www.gatsbyjs.com/
[9]: https://www.kontent.ai/