How To Lock Down Your Api_key and Why It’s Important

Run your app without specifying API keys in the code

Photo by Jon Moore on Unsplash

Do you leave your keys inside your car in a big parking lot? No? Then why do you expose your api_key in your GitHub projects?

Deploying apps using Cloud services is the norm but it comes with security complexities. Cloud services require credentials, often in the form of API tokens.

Sneaky hackers search for these tokens to use as computing resources for mining cryptocurrency or to access sensitive data.

A common practice is scanning the web and public tools, such as GitHub, in the search of API keys which are unknowingly publicly accessible. This presents significant risks to both users and Cloud-service providers.


The Problem With API Keys

The main problem is that, historically, devs store api_key in the code.

The code below is not that difficult to find.

# src/keys/api_key.js
SOME_SERVICE_API_KEY = '2es8-473t-43ef-a34d' # Don't tell anyone!

Many developers constantly expose their API keys in the code, then they push into their repo, and voilà!

Obviously, this is the least safe method, as you are disclosing an important secret which highly increases the risk of leaking your secret.

I had to develop a project as an assignment and one of the requirements was to consume The Movie Database API service.

The way to do it is by providing the api_key in each call to the service. In my case, the key won't be completely hidden when the app is running.

Anyway, it represented a good opportunity for me to learn how to avoid storing the key in the code itself. I took the opportunity to share my experience here. You can get all the details in my GitHub project.

I implemented the assignment using ES6, TypeScript, and webpack. Just note that this solution would work in any other setting that uses webpack.


Add the API Keys Using Webpack

In my case, I wanted a very simple solution where I would just set the api_key for each deployment script.

I used webpack's DefinePlugin, which allowed me to create the api_key as a global constant which can be configured at compile time.

new webpack.DefinePlugin({
// Definitions...
});

This definition in my webpack.config file looks like this:

Note that setting module.exports with a function, instead of assigning directly the object, is important. Otherwise, you don't get access to the env variable.


Deep Into the Configuration File

The configuration should be able to serve the app in development and production mode.

Of course, if you are using webpack, it also includes HMR (Hot Mode Reload).

This is how to serve the app in development mode:

TMDB_API_KEY=<yourTmdbApiKey>
npm run serve-dev -- --env.apiKey=${TMDB_API_KEY}

And, serve it in production mode:

TMDB_API_KEY=<yourTmdbApiKey>
npm run build:webpack -- --env.apiKey=${TMDB_API_KEY} && \
npm run serve-prod

Please note that, in both cases, I need to tell webpack explicitly that I am passing the key.

See that -- as an argument on its own is standardized across all Unix commands. It means that further arguments should be treated as positional arguments, not options.

In this context, it means that the parameters after the -- should be sent to the command serve-dev or build:webpack, depending on the script you are running.

I added the following code at the beginning of my webpack file, to make sure that whoever runs the app is aware that the api_key is needed to run the scripts and load the app.

At this point, I have everything ready in my config file. I am importing this module and returning the api_key that I get after running the commands.

I have the following code in the api_key.js file, which is located where I’m consuming the service.

And the script in my package.json looks like:


Test Scripts

But, what happens for the test scripts?

Normally we don't need the API keys for testing, we should be mocking the calls. I know, but in my case, I have some code in the tests that indirectly calls the function that returns the api_key.

If you are in a similar situation, you can do the same as I did. To avoid the use of a proper api_key, I added this code to babel.js:

Now, just run the npm test script without passing the apy_key:

npm run test

That's is all you need and you should now be ready to run your app without specifying API keys in the code.

Thanks for reading! If you have any suggestions or ideas, please let me know.

Better Programming

Advice for programmers.

Liliana Nuño Silva

Written by

React Fullstack developer, my opinions are my own

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade