DEV Community

Cover image for How to Secure Your HTTP APIs
Liz Parody
Liz Parody

Posted on

How to Secure Your HTTP APIs

If you are building an application with HTTP APIs that serve sensitive data, one of the key considerations is security. You want to ensure that callers of your API are authorized to make those calls before they are granted access to sensitive information or perform sensitive operations.

This post will review a few HTTP API access control approaches, from simple API keys to OAuth. It will also discuss a more complex yet flexible scheme that enables your customers to influence how access control decisions are made, based on how we approached securing API traffic to Fusebit.

A Multi-Tenant Cloud Application

Most web applications with APIs built today are multi-tenant. They have many customers or users (called tenants). The expectation is that your secure REST APIs enable your tenant’s access and control over their data, but not the data of other tenants of your app.

Let’s say you are building an application that enables stores to track their inventory. Each store is a separate tenant of your app. You expose REST API for inspecting and modifying a store’s inventory. It could look something like this:

app.get(/api/store/:storeId/inventory, searchStoreInventory);, createStoreInventoryItem);
app.get(/api/store/:storeId/inventory/:itemId, getStoreInventoryItem);
app.put(/api/store/:storeId/inventory/:itemId, updateStoreInventoryItem);
app.delete(/api/store/:storeId/inventory/:itemId, deleteStoreInventoryItem);
Enter fullscreen mode Exit fullscreen mode

You have signed up multiple stores as customers of your app. Your application security requires that each store can access and manipulate its own inventory, but not the inventory of other stores. Moreover, you may want to distinguish between individual callers acting on behalf of a single store, with some having only the read access to the inventory, while others both read and write.

Authentication and Authorization

It is useful to secure your HTTP APIs in two separate steps: authentication and authorization.

Authentication is the process of proving the identity of the caller. When the authentication process is complete, you know whether Daisy or John made the call.

Once you understand who is making the request (who the authenticated user is), the next step is to determine what permissions the caller has. This process is authorization. When the authorization is complete, you know that John can only look up the inventory of the “Pet’s Parlor” store, while Daisy can both look up and modify the inventory of the “International Burger Machines” store.

It is interesting to note that as a developer securing the HTTP APIs at the application level, you mostly care about the permissions of the caller, not their identity (unless required by law, web server logs, or for auditing purposes). When someone shows up in a grocery store to buy a bag of potatoes with cash, the clerk only cares if they carry the prerequisite amount of money, not who they are. This is important because it allows for flexibility as to when and where the authentication and authorization decisions are made.

API Keys

Using API keys has been the norm in securing HTTP APIs of RESTful web services for a long time, and many established applications and platforms like Stripe or AWS continue using API keys today.

OAuth providers api key

An API Key is a secret shared between the application and the caller. The caller authenticates a call to the HTTP APIs by proving ownership of the API key. It can be as simple as attaching the API key to the request, for example, in the Authorization HTTP request header or a URL query parameter. It can also be as complex as digitally signing selected parts of the request payload with that key.

HTTP GET /api/store/123/inventory
Authorization: Bearer {api-key}
Enter fullscreen mode Exit fullscreen mode

The example above is using the Bearer scheme of the Authorization HTTP header, which is the preferred way of passing in API keys in web API calls when the user agent is an application. Some secure API endpoints use the HTTP basic authentication scheme instead. In this scheme, the token passed in is an encoded combination of a username and password, and as such more suitable in situations where the user agent is a web browser with a human in front of it.

Since API keys are usually scoped to a particular tenant of an application, proving ownership of an API key implicitly authorizes the caller to perform operations on that tenant. If the authorization decisions require finer granularity, like in our store inventory app example, you can choose to have a concept of API keys with specific permissions associated with them. This is the mechanism Stripe implemented, called “Restricted keys” in the screenshot above.

From the perspective of the developers starting to work with your APIs, the biggest advantage of API keys is simplicity. It is a simple concept to start with, and it is easy to attach an API key to a request using any HTTP client.

API keys have several drawbacks though, the severity of which depends on your specific application.

Delegating access to your APIs is only possible through sharing the API key. This is akin to sharing your Twitter password with your marketing team, your cell phone PIN with your kids, or your bank account password with a financial aggregation application. Over time it leads to dilution of control and overall reduction of security. It also makes key rollover (next) harder to manage.

API keys are long-lived, and compromised keys require a rollover. During the rollover, a new key must be generated, and every system using the old key must be updated. This means work for developers working with your APIs and for you. This is usually done in three stages to reduce downtime. First, a new key is generated, and your app accepts both old and new keys. Then, all systems calling your APIs are reconfigured to use the new key. Lastly, the old key is removed from your app, and it only accepts the new key going forward. This process can take a long time as it is usually human-driven.

Read the full blog post here

Discussion (0)