API Security Best Practices
Web APIs are quite vulnerable. Especially with the rising threat of cyberattacks, securing these integrations has become business-critical. Thankfully, by following a few best practices, API providers can ward off many potential vulnerabilities. Below, we cover top API security best practices, which are good things to keep in mind when designing and creating APIs.
Our first recommendation is to always put your API behind a gateway. API gateways centralize traffic features and apply them to every request that hits your API. These features may be security-related, like rate limiting, blocking malicious clients, and propper logging. Or, they may be more practical and business-related, like path and headers rewriting, gathering business metrics, and so on.
Not having these controls could easily result in a serious security threat. Without a gateway, API providers would have to reinforce each endpoint with these features one-by-one. An API gateway eases the process of adding or fixing these features. Thankfully, there are plenty of API Gateway products available on the market.
Next, do not let your APIs or Gateways issue Access or Refresh Tokens. A centralized OAuth Server should always issue such tokens. Issuing tokens requires many complex processes: authenticating the client, authenticating the user, authorizing the client, signing the tokens, and other operations. All these functions require access to different data, such as client information or the preferred authentication mechanism. Furthermore, if many entities issue and sign tokens, it becomes increasingly challenging to manage all the credentials used to sign the issued keys. Only one entity can safely handle these processes — an OAuth Server.
When APIs are concerned, using JWTs as access and refresh tokens is a good practice. Services that receive JWTs can leverage claim information to make informed business decisions: Is the caller allowed to access this resource? What data can the caller retrieve?
However, when tokens are exposed outside of your infrastructure to third-party clients, you should use opaque tokens instead of JWTs. Information in a JWT is available to everyone and easy to decode. If JWT data is public, privacy becomes a concern. You must thus ensure that no sensitive data ends up in the JWT's claims. But, if you share JWTs with your third-party clients, chances are that they will start depending on the data in the JWT. Changing claims in a JWT could result in a Breaking Change, requiring costly implementation upgrades in all third-party clients.
If you want to use opaque tokens externally but also benefit from JWTs in your internal communication, you can use one of two approaches: thePhantom Token Approach or the Split Token Approach. Both involve an API Gateway in the process of translating an opaque token into a JWT.
OAuth scopes limit the capabilities of an Access Token. If stolen client credentials have limited scopes, an attacker will have much less power. Therefore, you should always issue tokens with limited capabilities. Verification of token scopes can be done at the API Gateway to limit the malicious traffic reaching your API. You should use Scopes to implement coarse-grained access control. This control could include checking whether a request with a given access token can query a given resource or verifying the client can use a given Content-Type.
You should always implement fine-grained access control at the API level. This access control should be architected so that even if a malicious request slips through the Gateway, the API will still reject it. This practice safeguards against situations in which attackers bypass the Gateway.
The API should verify whether or not the request can reach the given endpoint. It should also check whether the caller has rights to the data and what information can be returned based on the caller's identity (both for the client and user). OWASP lists broken access control as one of the top 10 API security vulnerabilities, so it's worth remembering this one.
Zero-trust is not just a buzzword — your API should limit trust to incoming traffic. Period. The first step toward building zero-trust is using HTTPS for all API traffic. If possible, use HTTPS internally so that traffic between services cannot be sniffed.
Your services should always verify incoming JWTs, even if they are transformed from an opaque token by the Gateway. This again helps to mitigate situations where a request manages to bypass your gateway, preventing a malicious actor from operating inside your company or infrastructure.
Proper JWT validation is crucial for the security of your APIs. Yet, if every team implements their own JWT validation solution, you risk increasing overall system vulnerability. Mistakes are more common, and it's difficult to fix bugs.
Instead, create a company-wide solution for JWT validation, preferably based on libraries available on the market and tailored to your API's needs. Standardizing a company-wide JWT validation process will help guarantee the same level of security across all your endpoints. When issues arise, teams can resolve them more quickly. For security-sensitive tasks like JWT validation, quick threat resolution is incredibly important.
Do not mix authentication methods for the same resources. Authentication methods can have different security levels, such as Basic Authentication and Multi-Factor Authentication. If you have a resource secured with a higher level of trust, like a JWT with limited scopes, but allow access with a lower level of trust, this can lead to API abuse. In some cases, this could be a significant security risk.
Do not leave any of your APIs unprotected. Even internal APIs should have protections implemented. This way, you're sure that the API is protected from any threat from inside your organization.
APIs are commonly created for internal use only and made available to the public later on. In such scenarios, proper API security tends to be overlooked. When published externally, the API becomes vulnerable to attacks.
Remember that security by obscurity is not recommended. Just because you create a complicated name for an endpoint or Content-Type does not mean the API will be secure. It's only a matter of time before someone finds the endpoint and abuses it.
If you have internal clients operating only inside your network, you can have your OAuth Server issue JWTs for such clients instead of opaque tokens. This will avoid unnecessary token translations. However, you should only apply this strategy if the JWTs do not leave your network. If you have external clients, or if the tokens are used externally, you should hide them behind an opaque token, as noted before.
To verify a JWT's integrity, an API must access a public key. You can accomplish this in a couple of ways: you can hardcode the key's value or query some endpoint at your service startup and cache the result.
The recommended method is to obtain a key from a JWKS endpoint exposed by the OAuth server. The API should cache the downloaded key to limit unnecessary traffic but should query the JWKS endpoint again whenever it finds a signing key it doesn't know.
This allows for a simple key rotation, which the OAuth Server can handle on-demand without impeding the API services. Using key sets instead of keys also allows a seamless key rotation for the clients. The OAuth Server can begin issuing new tokens signed with a new key and validate existing tokens as long as the old public key is part of the key set.
Maintaining high standards for your APIs, both from a security and design point of view, is not a trivial task. Therefore, consider splitting responsibility between different groups of people and having other teams audit your APIs.
There are different approaches to setting up governance over your API. You could have a dedicated team of API experts review the design and security aspects, or create a guild of API experts picked from different groups to offer guidance. However you organize governance, ensure you always have additional eyes checking your APIs.
As defined by the JWT specification, a claim is a piece of information asserted about a subject. It's good practice to have these claims asserted by a centralized OAuth Server — this makes it easier to control which claims appear in your tokens. This is important for privacy and security reasons.
Whether calling internal or external services, all APIs should only use claims asserted by the centralized server and should not add additional information nor issue tokens. Managing claims centrally allows you to control the information flowing between the APIs to ensure they do not leak excess data.
Just because your API security isn't breached doesn't mean that everything is fine. You should gather metrics and log usage of your API to catch any unwanted behavior. Watch out for requests iterating over your IDs, requests with unexpected headers or data, customers creating many clients to circumvent rate limits, and other suspicious cues. Losing data due to API abuse can be just as harmful to your business as a hacker breaking through the security.
Maintaining high-standard API security is a paramount concern. As we've seen above, there are many technical strategies to consider when designing your authorization processes, which, if undermined, can directly affect API security. A stronger foundation is only made possible with a secure, centralized OAuth server responsible for certificate generation and handling claims. Many suggestions also revolve around treating internal APIs with the same care as public-facing endpoints. By following these protective measures, you can sufficiently safeguard APIs and thwart unwanted behavior.