When accessing a landscape with internal and external users, it is important to take security very seriously. In the case of an API gateway, it is crucial that authentication and authorization associated with access to this gateway is properly configured. In this blog we compare three ways to achieve this: API keys, HTTP Basic Authentication and OAuth. We discuss these three and also look at some of the advantages and disadvantages of each method.
Using API keys is a way to authenticate access to an API on tenant, user or application level. It does not refer to an actual user, a API key is used (Authentication). In an API request, the key is added so that it can be used to identify the requestor and authorize the request (Authorization). The key can also be used for rate-limiting, tracking statistics, and other similar actions or principles. There are several ways an API can handle an API key. Some APIs require query parameters, some use the “header authorize” variant, and there are cases where the use of parameters in the body or elsewhere is necessary. Below is an example of Google Cloud API.
- Simple: While most providers use different methods, adding a key to an API request is fairly simple.
- Identification is difficult: The API key only identifies the application and not necessarily the user of the application.
- Difficult to keep the key secret: For server-to-server communication it is possible to hide the key with TLS and restrict access to use in backend scenarios. However, there are many different types of clients that want to consume the APIs, this makes it difficult to hide the keys.
HTTP Basic Auth
HTTP Basic Auth is a simple method, where an HTTP request is authenticated by means of a username and password. This technique uses a header called “Authorization”, this contains a base64 encrypted representation of the username and password. Depending on the use case, HTTP Basic Auth can authenticate the user of the application or the application itself.
In the case where HTTP Basic Auth is deployed for an API Gateway, this header value “Authorization” is sent with each request. This situation is similar to the use of API Keys, where the credentials are used to authenticate the application.
As with API Keys, these credentials can be leaked to third parties. The chance that credentials are traceable in logging data is smaller, because they are sent in a header. This chance is greater in the case of a query or path parameter that would contain an API Key.
Using HTTP Basic Auth for user authentication is usually not recommended, because sending the user credentials for every request is considered a “bad practice”. If HTTP Basic Auth is used for only one request, the application still needs to collect user credentials. The user has no means of knowing which application they are being used for and the only way to revoke access is to change the password.
- Standardized: HTTP Basic Auth is a standardized way to send credentials. The header always has the same structure and the components are easy to implement.
- Easy to use: it can provide application authentication in server-to-server environments.
When a user is authenticated, the application must store the password. From the user’s perspective, it is not clear how the application persists the password. There is no way for the user to revoke access other than by changing the password. Passwords are long-term tokens and if an “attacker” has obtained a password, it usually goes unnoticed. When this authentication is used to authenticate the user then multi-factor authentication is no longer possible.
Token based authentication with OAuth 2.0
A token-based architecture is based on a principle, in which all services receive a token as proof that the application may invoke the service. The token is issued by a third party that can be trusted by both the application and the service. Currently, the most popular protocol for obtaining these tokens is OAuth 2.0, specified in RFC 6749.
OAuth specifies a way of working in which an application or user can request access to services and receive a token as proof that access has been granted. To explain how OAuth works, we specified a fictional use case:
User Alice has an account with a service where she can report the current indoor temperature of her home. Alice also wants to give a third-party application access to read the temperature data so that they can plot the temperatures in a graph and to support references to data from other services.The (temperature) service provides an API Gateway, in which applications from other parties can easily access the data, in this case the temperature data. But how do we only make Alice’s data available to the application?
Managing the login credentials:
Using “Basic Authentication”, the application can collect Alice’s username and password for the temperature service and use it to retrieve the service’s data. The temperature service can then verify the username and password and return the requested data.
However, as we mentioned earlier, there are a few problems with this approach:
- The user must trust the application with the credentials.
The user has no means of knowing what the credentials are being used for.
- The only way for the user to revoke access is to change the password.
- The request is not authenticated.
- The extent of the access cannot be verified.
The user has given away full access to the account.
- Two factor authentication cannot be used.
The result is that a need has been created for services to use “application specific passwords”, this provides additional passwords for your account that can be used by applications.
This eliminates the need to give away the actual password, but it also usually means that full access to the account is given away. On the service provider side, logic can be incorporated around combining specific passwords to give access to certain components with API Keys, which could also limit access, but this requires a lot of customization. This brings us to a more recent and also better way of authentication, OAuth.
The OAuth way
Let’s see how to solve this problem using an OAuth 2 strategy. For better authentication, the temperature service must publish an authorization server responsible for issuing tokens. This authorization server allows third-party applications to register and receive credentials for their application to request access on behalf of users.
To request access, the application can direct the user's browser to the authorization server with parameters:
This request takes the user to the temperature service authorization server, where the authorization server can authenticate Alice using any available method. Because this is done in the browser, multiple factors are possible and are the only ones who see the data the temperature service and the account owner.
Once Alice has authenticated herself, the authorization server can ask for third-party authorization. In this example, the read_temperature scope is requested so that the authorization server can make a specific request. Once Alice accepts, the client can authenticate itself. A token is issued as proof that Alice has accepted the delegated access and this is returned to the third party application. Now the third party application can call the API using the received token. The token is sent along with the request by adding it to the Authorization header with the keyword Bearer as follows:
After receiving the request, the service can validate the token and see that Alice has authorized the application to read the lists of temperatures from her account and return the data to the application.
The issued token can be returned in two ways, either by returning a reference to the token data or by returning the value of the token directly. For the reference token, the service must send a request to the authorization server to validate the token and return the associated data. This process is called “introspection” and an example response looks like this:
In this response we can see that the user Alice has granted the application third_party_graphs access to her account, containing the scope of read_temperatures. Based on this information, the service can decide whether to allow or deny the request.
The client_id can also be used for statistics and rate-limiting of the application. Note that we only got the username of the account in the example, but because the authorization server does the verification, it can also return additional claims in this response (such as account type, address, shoe size, etc.) Claims are parameters that allow the service to make an informed authorization decision.
A JSON Web Token (JWT) is typically used to return the value. This token can be signed or encrypted, allowing the service to verify the token by simply using the public key of the trusted authorization server. If you want to read about several possibilities and alternatives regarding the deployment of different token types you can click here.
We see big differences in the OAuth method compared to Basic Authentication:
- Alice only gave her credentials to the trusted website.
- Multi factor authentication can still be used.
- Alice can easily change the application access, without the need for a password change.
- Alice can grant the third party application access to specific information from her account.
- Claims against the user can be honored immediately at the time of the request and no additional checks are required.
- The 'authentication' flow is fully standardized.
In the above use case only the user flow is described, but OAuth of course specifies alternative flows for obtaining tokens in server to server environments. If you want more information about the different flavors of processing and flows optimally supported with OAuth the following article is very interesting: 8 types of oauth flows.
But which way is better?
Since OAuth 2 was developed at a time of increasing use of APIs, most use cases involving API Key or Basic Authentication have been considered and included within the protocol. Therefore, the use of OAuth 2 is preferred over API Keys and Basic Authentication.
For small and specific scenarios, it may be appropriate to use an API Key or even Basic Authentication. But anyone who is building a system and plans to scale this system will want and also need to look at a token-based architecture, for example a Neo Security Architecture.
They best way to arrange the security of your API gateway depends on your use case. In the case that you have a smaller and more specific case, you use an API key or Basic Authentication. But when you have a big use case where security is essential, the most logical choice is OAuth 2.
Hopefully you know a little bit more about arranging security for an API gateway. Do you want to know some more or do you have a interesting case where you could use some help? Reach out, maybe we can help you!
By Leo Bekhuis, Software Engineer @ eMagiz