DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Build a Simple REST API Using Python Flask and SQLite (With Tests)
  • How to Create a Successful API Ecosystem
  • MCP Servers: The Technical Debt That Is Coming
  • How to Merge HTML Documents in Java

Trending

  • Ensuring Configuration Consistency Across Global Data Centers
  • Navigating the LLM Landscape: A Comparative Analysis of Leading Large Language Models
  • Building AI-Driven Intelligent Applications: A Hands-On Development Guide for Integrating GenAI Into Your Applications
  • Next-Gen IoT Performance Depends on Advanced Power Management ICs
  1. DZone
  2. Data Engineering
  3. Databases
  4. Hide Your API Keys With an API Proxy Server

Hide Your API Keys With an API Proxy Server

The main goal of this article/tutorial is to demonstrate how to conceal public API keys by building an API proxy server using NodeJS.

By 
Pantelis Theodosiou user avatar
Pantelis Theodosiou
·
Aug. 11, 22 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
5.1K Views

Join the DZone community and get the full member experience.

Join For Free

In this article/tutorial, we are going to create an API Proxy Server using NodeJS, and the main reason behind this is to show you how to hide public API keys and not expose them in the public like I was doing in the past. All of us have created an application once just to get to know a new library or a framework, and the best way to achieve this is to use an open API (like TMDB).

Most of these open APIs require adding the API key in the request URL or in the headers before making the request. Either way, the API key can be stolen and used by people that are not actually own this key. As a result, you may end up with a suspended account, or your application not work as you've expected it to.

Remember this: The API keys belong to the server side of your application.

Without further talking, let's create this API Proxy server. For the sake of this article/tutorial, we are going to use Weather API.

Requirements

Before start coding, we need to have the followings:

  • API key
    Open the OpenWeatherMapAPI website, make a free account, go to My API keys and create one.
  • Basic knowledge of JavaScript and NodeJS
  • Coffee

Dependencies and Scripts

Create the application's project folder

Shell
 
cd ~/Documents/tutorials
mkdir api-proxy-server && cd api-proxy-server
npm init -y


Install required NPM packages

Shell
 
npm install -S express cors dotenv axios
npm install -D nodemon # for faster development


Prepare scripts inside package.json file

JSON
 
{
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon --config nodemon.json"
  }
}


Let's take a look at the project's folders and files just to have a clearer image of the structure.

 
server/
├── src
│   ├── utils
│   │   └── env.js
│   └── routes
│       └── index.js
├── package.json
├── nodemon.json
├── index.js
└── .env
3 directories, 6 files


Create an index.js and a nodemon.json file at the root of the project.

JSON
 
// nodemon.json
{
  "verbose": true,
  "ignore": ["node_modules/"],
  "watch": ["./**/*"]
}


Before we start editing the entry (index.js) file, we need to create two other useful files. The first one is the .env file where all of our environment variables live. It's going to be a bit reusable in order to be able to use it with other public APIs except OpenWeatherMap API.

 
API_PORT = 1337
API_BASE_URL = "https://api.openweathermap.org/data/2.5/weather"
API_KEY = "1d084c18063128c282ee3b41e91b6740" # not actually api key; use a valid one


And the other file is the src/utils/env.js which is responsible to read and export all the environment variables.

JavaScript
 
require("dotenv").config();

module.exports = {
  port: Number(process.env.API_PORT) || 3000,
  baseURL: String(process.env.API_BASE_URL) || "",
  apiKey: String(process.env.API_KEY) || "",
};


Now it's time to edit the main file and add some logic to this proxy server application.

JavaScript
 
// imports
const express = require("express");
const cors = require("cors");
const env = require("./src/utils/env");

// Application
const app = express();

// Middlewares
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());

// Routes
app.use("/api", require("./src/routes")); // Every request that starts with /api will be handled by this handler

// This route will handle all the requests that are not handled by any other route handler
app.all("*", (request, response, next) => {
  return response.status(404).json({ message: "Endpoint not found!" });
});

// Bootstrap server
app.listen(env.port, () => {
  console.log(`Server is up and running at http://localhost:${env.port}`);
});


Things here are very simple; it's a basic ExpressJs server application. On the top, we've got the required imports. Then we have some needed middleware, such as the JSON middleware, which is responsible to parse incoming requests with JSON payloads and is based on body-parser. Next, we have the routes where here we manage the endpoints and their handlers. And lastly, we've got the bootstrapping of the server.

Let's take a look at the handler of the /api route.

JavaScript
 
// server/src/routes/index.js
const router = require("express").Router();
const { default: axios } = require("axios");
const env = require("../utils/env");

// [GET] Current weather data
router.get("/", async (request, response, next) => {
  try {
    const query = request.query || {}; 
    const params = {
      appid: env.apiKey, // required field
      ...query,
    };
    const { data } = await axios.get(env.baseURL, { params });

    return response.status(200).json({
      message: "Current weather data fetched!",
      details: { ...data },
    });
  } catch (error) {
    const {
      response: { data },
    } = error;
    const statusCode = Number(data.cod) || 400;
    return response
      .status(statusCode)
      .json({ message: "Bad Request", details: { ...data } });
  }
});

module.exports = router;


The GET request handler function is taking as inputs the query fields that we've provided when we call it.

For example, if we didn't have this API Proxy server, our request would look like this https://api.openweathermap.org/data/2.5/weather?q=Thessaloniki,Greece&appid={API key}, but now that we've got it, our request looks like this http://localhost/api?q=Thessaloniki,Greece. There is no need to add the required field appid because the proxy server adds it by itself as a request parameter. We spared not showing the API key while we make the request on the OpenWeatherMap API.

Summary

The main concept is to hide your public API keys behind an API Proxy Server in order to prevent users to steal your keys. To achieve this, it is to create endpoints that wrap the endpoints of the actual open API providing the API key inside the proxy server as an environment variable in every request that needs this key. The obvious con of this approach is that this is a time-consuming process and, in some cases, is not even needed.

You can get the source code of this API Proxy server here.

What's Next

I was thinking to add some features to this proxy server. One of these is to add caching functionality in order to serve the data that was recently requested faster. The other one is to add a rate limiter in order to prevent users from overusing the API and crashing the server.

Drop a comment if you've thought of another solution to hide your API keys or if you have any tips or tricks to tell me about.

API

Published at DZone with permission of Pantelis Theodosiou. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Build a Simple REST API Using Python Flask and SQLite (With Tests)
  • How to Create a Successful API Ecosystem
  • MCP Servers: The Technical Debt That Is Coming
  • How to Merge HTML Documents in Java

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!