What is the best API security approach to adopt? Amid rising API attacks, API security should be front and central for modern enterprises. However, not all API security implementations are the same, and not all are effective. Too often, weak API approaches overlook a significant concern: identity. This must change, as an identity focus is crucial to fully evolve the security and efficiency of an API.
So, how do we encapsulate identity with APIs and make it useful? The answer lies in Claims. APIs that utilize OAuth and OpenID Connect can take advantage of Claims, an advanced form of trust.
Are API Keys or Basic Authentication Enough?
You may be thinking: aren't API keys sufficient? The answer is no. This method is very basic, wrought with vulnerabilities. Not only are keys constantly compromised, but API key verification relies on machine-to-machine verification unbound to the user's identity. Also, this method only provides authentication, the act of proving an assertion, and does not cover authorization at all.
Though Basic Authentication and API keys are becoming less common, many organizations still use this kind of implementation to verify API calls. Most APIs established this authentication years ago, and some never evolved from there. (If you're in this boat, now is the time to do something about it).
A better approach for API security is to use Access Tokens for authentication within a token-based architecture. Such Access Tokens delineate the type of client, such as an app, machine, or end-user. Since this approach enables privileged access, it helps in environments where the separation of internal and external users is required. In addition, token-based authentication provides better auditing since user identity is part of the request.
However, one issue with this approach is that when tokens are only used for authentication, there's no guarantee that the user has enough privileges to perform the API operation. This means you must rely on other mechanisms to prevent hacks for privileged access. In other words, this strategy doesn't answer what the requesting party is allowed to do.
Using a token-based architecture for authorization is a more evolved approach. Authorization delineates privileges for the requesting party, answering what you are allowed to do.
A great benefit of using OAuth is Scopes, which can be understood as "named permissions" within a token. These Scopes can specify what an access token can be used for. You can use predefined scopes to generate standard identity arguments. Or, more commonly, you can create custom Scopes for your API.
However, Scopes still present certain limitations. To get a better understanding, let's consider an eCommerce store. We introduce Scopes so that accessing the public web store and back-office requires different privileges. However, some operations overlap. For example, we use the Scope LIST to list invoices in the billing API. The ID for LIST is in the URL or passed as a request parameter. Thus, it's possible to manipulate the call to list invoices for another user. Thus, the Scope is not sufficient. Scopes lock down what the client application is allowed to do — since they are only names and not values, they don't help with the particular user's permissions. Instead, Claims should be used so that the parameters are baked into the token with values. Then, it's easy to separate back office privileges from web store privileges.
One challenge with the Scope-only approach is that the system must take extra care of how identity information is used. When identity is built directly into the API, logic errors may be discovered and exploited. It also introduces a higher degree of system complexity, as some API request parameters may rely on other API responses or other conditions. What happens when one API calls another API that fails? Or, what if the data request is full of errors? You can't always assume the data passed from one API to the next is always correct. These realities cause cascading issues of trust, which quickly become an intertangled mess.
Centralized Trust Using Claims
The most evolved pattern for an API security platform is to adopt centralized trust using Claims. This involves centralizing trust with Claims and possibly signed JSON Web Tokens (JWTs) as well. In doing so, we solve all the problems outlined above.
What are JWTs? Well, a JWT is a signed piece of data. It is NOT a protocol. OAuth flows utilize JWTs to carry identity information. In addition, JWTs contain Scopes.
And Claims? Claims are essentially assertions. For example, consider a written statement: "Jacob is an identity specialist, says Travis." This Claim has a Subject (Jacob), an Attribute (that he is an identity specialist), and an Asserting Party (Travis). If you trust Travis, then you trust the Claim. Many Attributes can make up the identity. There are Subject attributes, like name, age, height, or weight. In this case, the Asserting Party would be the police or tax authorities for these attributes. There are also Context Attributes, such as the situation, timing, location, or weather.
Instead of trusting the attributes themselves, it is far better to trust claims made by familiar parties. Identity systems use Claims with a similar anatomy for verification. If you trust the OAuth Server that issues keys, then you trust the Claim being made.
JWTs Require OAuth and OpenID Connect
For centralized trust to function, authorization systems require stable protocols. Just like how street traffic systems follow common protocols, identity systems require their own shared open standards. These protocols are OAuth and OpenID Connect, which can share secure asserted data within JWTs for verification.
Claims: Highly-Evolved Identity-Based API Security
Trust is a subjective thing. For example, should we trust keys, tokens, passwords, machines, or users in designing a secure API-based system?
As the different approaches outlined above demonstrate, highly mature APIs place trust in very few sources. Primarily, these evolved APIs place trust in the issuer of tokens. Of course, this does not guarantee truth but is the closest representation to validating the identity of the requesting parties. Furthermore, standardizing this process with centralized trust removes spaghetti code and wasted effort on custom code.
Essentially, the pinnacle of API security is to trust claims, not attributes. When building an identity-based API security system based on claims, remember some best practices:
Organize sensitive data only to be reachable by the OpenID Connect server.
Include identity data in access tokens, and keep contextual data to a minimum.
Use Opaque tokens on the public Internet and use JWTs internally.
Limit data exposure only to when the client needs it.
Avoid app-specific rules.
Without advanced security, APIs instantly become vulnerable with a rogue key left in a Github repository, as several incidents have proven. As a result, API providers must make smarter security decisions that safeguard the integrity of the entire platform. For further insights on evolving your API security posture, consider reading The Security Maturity Model article.